From 3185fb481ce5f1d89e2250742c0e1678732dfe20 Mon Sep 17 00:00:00 2001 From: Joseph Schuchart Date: Mon, 6 Nov 2017 18:23:46 +0900 Subject: [PATCH 01/24] Add dart_accumulate_blocking_local --- .../include/dash/dart/if/dart_communication.h | 34 ++++++- dart-impl/mpi/src/dart_communication.c | 93 +++++++++++++++++++ 2 files changed, 124 insertions(+), 3 deletions(-) diff --git a/dart-if/include/dash/dart/if/dart_communication.h b/dart-if/include/dash/dart/if/dart_communication.h index 072d506c9..77e67e8f7 100644 --- a/dart-if/include/dash/dart/if/dart_communication.h +++ b/dart-if/include/dash/dart/if/dart_communication.h @@ -249,6 +249,34 @@ dart_ret_t dart_accumulate( dart_datatype_t dtype, dart_operation_t op) DART_NOTHROW; + +/** + * Perform an element-wise atomic update on the values pointed to by \c gptr + * by applying the operation \c op with the corresponding value in \c value + * on them. + * + * DART Equivalent to MPI_Accumulate. In contrast to \ref dart_accumulate, this + * function blocks until the local buffer can be reused. + * + * \param gptr A global pointer determining the target of the accumulate + * operation. + * \param values The local buffer holding the elements to accumulate. + * \param nelem The number of local elements to accumulate per unit. + * \param dtype The data type to use in the accumulate operation \c op. + * \param op The accumulation operation to perform. + * + * \return \c DART_OK on success, any other of \ref dart_ret_t otherwise. + * + * \threadsafe_data{team} + * \ingroup DartCommunication + */ +dart_ret_t dart_accumulate_blocking_local( + dart_gptr_t gptr, + const void * values, + size_t nelem, + dart_datatype_t dtype, + dart_operation_t op) DART_NOTHROW; + /** * Perform an element-wise atomic update on the value of type \c dtype pointed * to by \c gptr by applying the operation \c op with \c value on it and @@ -706,18 +734,18 @@ dart_ret_t dart_recv( /** * DART Equivalent to MPI sendrecv. * - * \param sendbuf Buffer containing the data to be sent by the + * \param sendbuf Buffer containing the data to be sent by the * source unit. * \param send_nelem Number of values sentby the source unit. * \param send_dtype The data type of values in \c sendbuf. * \param dest Unitthe message is sent to. - * \param send_tag Message tag for the distinction between different + * \param send_tag Message tag for the distinction between different * messages of the source unit. * \param recvbuf Buffer for the incoming data. * \param recv_nelem Number of values received by the destination unit. * \param recv_dtype The data type of values in \c recvbuf. * \param src Unit sending the message. - * \param recv_tag Message tag for the distinction between different + * \param recv_tag Message tag for the distinction between different * messages of the destination unit. * * \return \c DART_OK on success, any other of \ref dart_ret_t otherwise. diff --git a/dart-impl/mpi/src/dart_communication.c b/dart-impl/mpi/src/dart_communication.c index 7d223e3bd..202ddb530 100644 --- a/dart-impl/mpi/src/dart_communication.c +++ b/dart-impl/mpi/src/dart_communication.c @@ -438,6 +438,99 @@ dart_ret_t dart_accumulate( return DART_OK; } + +dart_ret_t dart_accumulate_blocking_local( + dart_gptr_t gptr, + const void * values, + size_t nelem, + dart_datatype_t dtype, + dart_operation_t op) +{ + MPI_Datatype mpi_dtype; + MPI_Op mpi_op; + dart_team_unit_t team_unit_id = DART_TEAM_UNIT_ID(gptr.unitid); + uint64_t offset = gptr.addr_or_offs.offset; + int16_t seg_id = gptr.segid; + dart_team_t teamid = gptr.teamid; + mpi_dtype = dart__mpi__datatype(dtype); + mpi_op = dart__mpi__op(op); + + dart_team_data_t *team_data = dart_adapt_teamlist_get(teamid); + if (dart__unlikely(team_data == NULL)) { + DART_LOG_ERROR("dart_accumulate ! failed: Unknown team %i!", teamid); + return DART_ERR_INVAL; + } + + CHECK_UNITID_RANGE(team_unit_id, team_data); + + DART_LOG_DEBUG("dart_accumulate() nelem:%zu dtype:%d op:%d unit:%d", + nelem, dtype, op, team_unit_id.id); + + dart_segment_info_t *seginfo = dart_segment_get_info( + &(team_data->segdata), seg_id); + if (dart__unlikely(seginfo == NULL)) { + DART_LOG_ERROR("dart_accumulate ! " + "Unknown segment %i on team %i", seg_id, teamid); + return DART_ERR_INVAL; + } + + MPI_Win win = seginfo->win; + offset += dart_segment_disp(seginfo, team_unit_id); + + // chunk up the put + const size_t nchunks = nelem / MAX_CONTIG_ELEMENTS; + const size_t remainder = nelem % MAX_CONTIG_ELEMENTS; + const char * src_ptr = (const char*) values; + + MPI_Request reqs[2]; + int num_reqs = 0; + + if (nchunks > 0) { + DART_LOG_TRACE("dart_accumulate: MPI_Accumulate (src %p, size %zu)", + src_ptr, nchunks * MAX_CONTIG_ELEMENTS); + CHECK_MPI_RET( + MPI_Raccumulate( + src_ptr, + nchunks, + dart__mpi__max_chunk_datatype[dtype], + team_unit_id.id, + offset, + nchunks, + dart__mpi__max_chunk_datatype[dtype], + mpi_op, + win, + &reqs[num_reqs++]), + "MPI_Accumulate"); + offset += nchunks * MAX_CONTIG_ELEMENTS; + src_ptr += nchunks * MAX_CONTIG_ELEMENTS; + } + + if (remainder > 0) { + DART_LOG_TRACE("dart_accumulate: MPI_Accumulate (src %p, size %zu)", + src_ptr, remainder); + + CHECK_MPI_RET( + MPI_Raccumulate( + src_ptr, + remainder, + mpi_dtype, + team_unit_id.id, + offset, + remainder, + mpi_dtype, + mpi_op, + win, + &reqs[num_reqs++]), + "MPI_Accumulate"); + } + + MPI_Waitall(num_reqs, reqs, MPI_STATUSES_IGNORE); + + DART_LOG_DEBUG("dart_accumulate > finished"); + return DART_OK; +} + + dart_ret_t dart_fetch_and_op( dart_gptr_t gptr, const void * value, From 8a459a70aa5e740bb14fe89239fdda5b967704ca Mon Sep 17 00:00:00 2001 From: Joseph Schuchart Date: Mon, 6 Nov 2017 18:24:45 +0900 Subject: [PATCH 02/24] Add GlobAtomicAsyncRef --- dash/include/dash/Atomic.h | 3 +- dash/include/dash/atomic/GlobAtomicAsyncRef.h | 405 ++++++++++++++++++ 2 files changed, 407 insertions(+), 1 deletion(-) create mode 100644 dash/include/dash/atomic/GlobAtomicAsyncRef.h diff --git a/dash/include/dash/Atomic.h b/dash/include/dash/Atomic.h index 4d0a6f3c0..499c09681 100644 --- a/dash/include/dash/Atomic.h +++ b/dash/include/dash/Atomic.h @@ -30,7 +30,7 @@ namespace dash { * dash::atomic::load(array.lbegin()) // not allowed * \endcode * \endnote - * + * * \code * dash::Array> array(100); * // supported as Atomic(value_t T) is available @@ -129,6 +129,7 @@ std::ostream & operator<<( } // namespace dash #include +#include #include #endif // DASH__ATOMIC_H__INCLUDED diff --git a/dash/include/dash/atomic/GlobAtomicAsyncRef.h b/dash/include/dash/atomic/GlobAtomicAsyncRef.h new file mode 100644 index 000000000..edb162614 --- /dev/null +++ b/dash/include/dash/atomic/GlobAtomicAsyncRef.h @@ -0,0 +1,405 @@ +#ifndef DASH__ATOMIC_ASYNC_GLOBREF_H_ +#define DASH__ATOMIC_ASYNC_GLOBREF_H_ + +#include +#include +#include +#include + + +namespace dash { + +// forward decls +template +class Atomic; + +template +class Shared; + +/** + * Specialization for atomic values. All atomic operations are + * \c const as the \c GlobRef does not own the atomic values. + */ +template +class GlobAsyncRef> +{ + /* Notes on type compatibility: + * + * - The general support of atomic operations on values of type T is + * checked in `dash::Atomic` and is not verified here. + * - Whether arithmetic operations (like `fetch_add`) are supported + * for values of type T is implicitly tested in the DASH operation + * types (like `dash::plus`) and is not verified here. + * + */ + + template + friend std::ostream & operator<<( + std::ostream & os, + const GlobAsyncRef & gref); + +public: + typedef T + value_type; + typedef GlobAsyncRef> + const_type; + +private: + typedef dash::Atomic atomic_t; + typedef GlobAsyncRef self_t; + +private: + dart_gptr_t _gptr; + +public: + /** + * Default constructor, creates an GlobRef object referencing an element in + * global memory. + */ + GlobAsyncRef() + : _gptr(DART_GPTR_NULL) { + } + + /** + * Constructor, creates an GlobRef object referencing an element in global + * memory. + */ + template + explicit GlobAsyncRef( + /// Pointer to referenced object in global memory + GlobPtr & gptr) + : GlobAsyncRef(gptr.dart_gptr()) + { } + + /** + * Constructor, creates an GlobRef object referencing an element in global + * memory. + */ + template + GlobAsyncRef( + /// Pointer to referenced object in global memory + const GlobPtr & gptr) + : GlobAsyncRef(gptr.dart_gptr()) + { } + + /** + * Constructor, creates an GlobRef object referencing an element in global + * memory. + */ + explicit GlobAsyncRef(dart_gptr_t dart_gptr) + : _gptr(dart_gptr) + { + DASH_LOG_TRACE_VAR("GlobRef(dart_gptr_t)", dart_gptr); + } + + /** + * Copy constructor. + */ + GlobAsyncRef( + /// GlobRef instance to copy. + const GlobAsyncRef & other) + : _gptr(other._gptr) + { } + + self_t & operator=(const self_t & other) = delete; + + inline bool operator==(const self_t & other) const noexcept + { + return this->get() == other.get(); + } + + inline bool operator!=(const self_t & other) const noexcept + { + return !(*this == other); + } + + inline bool operator==(const T & value) const = delete; + inline bool operator!=(const T & value) const = delete; + + operator GlobPtr() const { + DASH_LOG_TRACE("GlobRef.GlobPtr()", "conversion operator"); + DASH_LOG_TRACE_VAR("GlobRef.T()", _gptr); + return GlobPtr(_gptr); + } + + dart_gptr_t dart_gptr() const { + return _gptr; + } + + /** + * Checks whether the globally referenced element is in + * the calling unit's local memory. + */ + bool is_local() const { + return GlobPtr(_gptr).is_local(); + } + + /// atomically assigns value + GlobRef operator=(const T & value) const { + store(value); + return *this; + } + + /** + * Set the value of the shared atomic variable. + * The operation will block until the local memory can be re-used. + */ + void set(const T & value) const + { + DASH_LOG_DEBUG_VAR("GlobAsyncRef.set()", value); + DASH_LOG_TRACE_VAR("GlobAsyncRef.set", _gptr); + dart_ret_t ret = dart_accumulate_blocking_local( + _gptr, + reinterpret_cast(&value), + 1, + dash::dart_punned_datatype::value, + DART_OP_REPLACE); + DASH_ASSERT_EQ(DART_OK, ret, "dart_accumulate failed"); + DASH_LOG_DEBUG("GlobAsyncRef.set >"); + } + + /** + * Set the value of the shared atomic variable. + * The operation will return immediately and the memory pointed to + * by \c ptr should not be re-used before the operation has been completed. + */ + void set(const T * ptr) const + { + DASH_LOG_DEBUG_VAR("GlobAsyncRef.set()", *ptr); + DASH_LOG_TRACE_VAR("GlobAsyncRef.set", _gptr); + dart_ret_t ret = dart_accumulate( + _gptr, + reinterpret_cast(ptr), + 1, + dash::dart_punned_datatype::value, + DART_OP_REPLACE); + DASH_ASSERT_EQ(DART_OK, ret, "dart_accumulate failed"); + DASH_LOG_DEBUG("GlobAsyncRef.set >"); + } + + + /** + * Set the value of the shared atomic variable. + * The operation will block until the local memory can be re-used. + */ + inline void store(const T & value) const { + set(value); + } + + /** + * Set the value of the shared atomic variable. + * The operation will return immediately and the memory pointed to + * by \c ptr should not be re-used before the operation has been completed. + */ + inline void store(const T * ptr) const { + set(ptr); + } + + /** + * Atomically fetches the value + * + * The operation blocks until the value is available. However, previous + * un-flushed operations are not serialized. + */ + T get() const + { + DASH_LOG_DEBUG("GlobRef.get()"); + DASH_LOG_TRACE_VAR("GlobRef.get", _gptr); + value_type nothing; + value_type result; + dart_ret_t ret = dart_fetch_and_op( + _gptr, + reinterpret_cast(¬hing), + reinterpret_cast(&result), + dash::dart_punned_datatype::value, + DART_OP_NO_OP); + dart_flush_local(_gptr); + DASH_ASSERT_EQ(DART_OK, ret, "dart_accumulate failed"); + DASH_LOG_DEBUG_VAR("GlobRef.get >", result); + return result; + } + + /** + * Atomically fetches the value + * + * The operation will return immediately and is guaranteed to be + * completed after a flush occured. + * Previous un-flushed operations are not serialized. + */ + void get(T * result) const + { + DASH_LOG_DEBUG("GlobRef.get()"); + DASH_LOG_TRACE_VAR("GlobRef.get", _gptr); + value_type nothing; + dart_ret_t ret = dart_fetch_and_op( + _gptr, + reinterpret_cast(¬hing), + reinterpret_cast(result), + dash::dart_punned_datatype::value, + DART_OP_NO_OP); + DASH_ASSERT_EQ(DART_OK, ret, "dart_accumulate failed"); + } + + /** + * Load the value of the shared atomic variable. + * + * The operation blocks until the value is available. However, previous + * un-flushed operations are not serialized. + */ + inline T load() const { + return get(); + } + + /** + * Atomically executes specified operation on the referenced shared value. + */ + template + void op( + BinaryOp binary_op, + /// Value to be added to global atomic variable. + const T & value) const + { + DASH_LOG_DEBUG_VAR("GlobAsyncRef.op()", value); + DASH_LOG_TRACE_VAR("GlobAsyncRef.op", _gptr); + DASH_LOG_TRACE("GlobAsyncRef.op", "dart_accumulate"); + dart_ret_t ret = dart_accumulate_blocking_local( + _gptr, + reinterpret_cast(&value), + 1, + dash::dart_punned_datatype::value, + binary_op.dart_operation()); + DASH_ASSERT_EQ(DART_OK, ret, "dart_accumulate_blocking_local failed"); + } + + /** + * Atomic fetch-and-op operation on the referenced shared value. + * + * The value before the operation will be stored in \c result. + * The operation is guaranteed to be completed after a flush. + */ + template + void fetch_op( + BinaryOp binary_op, + /// Value to be added to global atomic variable. + const T & value, + T * result) const + { + DASH_LOG_DEBUG_VAR("GlobAsyncRef.fetch_op()", value); + DASH_LOG_TRACE_VAR("GlobAsyncRef.fetch_op", _gptr); + DASH_LOG_TRACE_VAR("GlobAsyncRef.fetch_op", typeid(value).name()); + dart_ret_t ret = dart_fetch_and_op( + _gptr, + reinterpret_cast(&value), + reinterpret_cast(result), + dash::dart_punned_datatype::value, + binary_op.dart_operation()); + DASH_ASSERT_EQ(DART_OK, ret, "dart_fetch_op failed"); + } + + /** + * Atomically exchanges value + */ + void exchange( + const T & value, + T * result) const { + fetch_op(dash::second(), value, result); + } + + /** + * Atomically compares the value with the value of expected and if thosei + * are bitwise-equal, replaces the former with desired. + * + * The value before the operation will be stored to the memory location + * pointed to by result. The operation was succesful if (expected == *result). + * + * The operation will be completed after a call to \ref flush. + * + * \see \c dash::atomic::compare_exchange + */ + void compare_exchange( + const T & expected, + const T & desired, + T * result) const { + DASH_LOG_DEBUG_VAR("GlobAsyncRef.compare_exchange()", desired); + DASH_LOG_TRACE_VAR("GlobAsyncRef.compare_exchange", _gptr); + DASH_LOG_TRACE_VAR("GlobAsyncRef.compare_exchange", expected); + DASH_LOG_TRACE_VAR( + "GlobRef.compare_exchange", typeid(desired).name()); + dart_ret_t ret = dart_compare_and_swap( + _gptr, + reinterpret_cast(&desired), + reinterpret_cast(&expected), + reinterpret_cast(result), + dash::dart_punned_datatype::value); + DASH_ASSERT_EQ(DART_OK, ret, "dart_compare_and_swap failed"); + } + + /** + * DASH specific variant which is faster than \c fetch_add + * but does not return value. + */ + void add(const T & value) const + { + op(dash::plus(), value); + } + + /** + * Atomic fetch-and-add operation on the referenced shared value. + * + * The value before the operation will be stored into the memory location + * pointed to by \c result. + * + * The operation will be completed after a call to \ref flush. + */ + void fetch_add( + /// Value to be added to global atomic variable. + const T & value, + /// Pointer to store result to + T * result) const + { + fetch_op(dash::plus(), value, result); + } + + /** + * DASH specific variant which is faster than \c fetch_sub + * but does not return value. + */ + void sub(const T & value) const + { + op(dash::plus(), -value); + } + + /** + * Atomic fetch-and-sub operation on the referenced shared value. + * + * The value before the operation will be stored into the memory location + * pointed to by \c result. + * + * The operation will be completed after a call to \ref flush. + */ + void fetch_sub ( + /// Value to be subtracted from global atomic variable. + const T & value, + /// Pointer to store result to + T * result) const + { + fetch_op(dash::plus(), -value, result); + } + + /** + * Flush all pending asynchronous operations on this asynchronous reference. + */ + void flush() + { + DASH_ASSERT_RETURNS( + dart_flush(_gptr), + DART_OK + ); + } + +}; + +} // namespace dash + +#endif // DASH__ATOMIC_ASYNC_GLOBREF_H_ + From 7c66ff6ad4abb8f2b7d1864161ac3b539e237c45 Mon Sep 17 00:00:00 2001 From: Joseph Schuchart Date: Mon, 6 Nov 2017 18:25:27 +0900 Subject: [PATCH 03/24] Add test cases for GlobAsyncAtomicRef --- dash/test/types/AtomicTest.cc | 110 ++++++++++++++++++++++++++++------ 1 file changed, 92 insertions(+), 18 deletions(-) diff --git a/dash/test/types/AtomicTest.cc b/dash/test/types/AtomicTest.cc index f8db77b37..0ee8c78d1 100644 --- a/dash/test/types/AtomicTest.cc +++ b/dash/test/types/AtomicTest.cc @@ -327,7 +327,7 @@ TEST_F(AtomicTest, AlgorithmVariant){ for(int i=0; i(dash::myid().id); value_t id_right = (myid + 1) % dash::size(); - + array[myid].store(myid); array.barrier(); ASSERT_EQ_U(id_right, array[id_right].load()); @@ -430,13 +430,13 @@ TEST_F(AtomicTest, AtomicInterface){ TEST_F(AtomicTest, MutexInterface){ dash::Mutex mx; - + dash::Shared shared(dash::team_unit_t{0}); - + if(dash::myid() == 0){ shared.set(0); } - + mx.lock(); int tmp = shared.get(); std::this_thread::sleep_for(std::chrono::microseconds(100)); @@ -444,34 +444,34 @@ TEST_F(AtomicTest, MutexInterface){ LOG_MESSAGE("Before %d, after %d", tmp, static_cast(shared.get())); // I guess here a flush is required, blocked by issue 322 mx.unlock(); - + dash::barrier(); - + while(!mx.try_lock()){ } // lock aquired tmp = shared.get(); std::this_thread::sleep_for(std::chrono::microseconds(100)); shared.set(tmp + 1); mx.unlock(); - + dash::barrier(); - + if(dash::myid() == 0){ int result = shared.get(); EXPECT_EQ_U(result, static_cast(dash::size()*2)); } - + dash::barrier(); - + // this even works with std::lock_guard { std::lock_guard lg(mx); int tmp = shared.get(); shared.set(tmp + 1); } - + dash::barrier(); - + if(dash::myid() == 0){ int result = shared.get(); EXPECT_EQ_U(result, static_cast(dash::size())*3); @@ -507,3 +507,77 @@ TEST_F(AtomicTest, AtomicSignal){ ASSERT_GT_U(count, 0); } } + + +TEST_F(AtomicTest, AsyncAtomic){ + + using value_t = int; + using atom_t = dash::Atomic; + using array_t = dash::Array; + + array_t array(dash::size()); + + // asynchronous atomic set + if (dash::myid() == 0) { + for (size_t i = 0; i < dash::size(); ++i) { + array.async[i].set(i); + } + } + array.barrier(); + + ASSERT_EQ_U(array[dash::myid()].get(), dash::myid()); + + int val = -1; + // kick off an asynchronous transfer + array.async[dash::myid()].get(&val); + + // wait for the above asynchronous transfer to complete + array.flush(); + ASSERT_EQ_U(dash::myid(), val); + + dash::barrier(); + + // test fetch_op + + if (dash::myid() == 0) { + std::vector vec(dash::size()); + for (size_t i = 0; i < dash::size(); ++i) { + array.async[i].exchange(0, &vec[i]); + } + array.flush(); + for (size_t i = 0; i < dash::size(); ++i) { + ASSERT_EQ_U(i, vec[i]); + } + } + + dash::barrier(); + + // atomic increment on unit zero + array.async[0].add(1); + + // flush on AtomicAsyncRef + array.async[0].flush(); + dash::barrier(); + if (dash::myid() == 0) ASSERT_EQ_U(array.async[0].get(), dash::size()); + + dash::fill(array.begin(), array.end(), 0); + + array.async[dash::myid()].fetch_add(dash::myid(), &val); + array.barrier(); + ASSERT_EQ_U(0, val); + + if (dash::myid() == 1) { + std::vector vec(dash::size()); + for (size_t i = 0; i < dash::size(); ++i) { + array.async[i].compare_exchange(i, 2*i, &vec[i]); + } + array.flush(); + for (size_t i = 0; i < dash::size(); ++i) { + ASSERT_EQ_U(i, vec[i]); + ASSERT_EQ_U(2*i, array[i].get()); + } + } + + dash::barrier(); + +} From ea9f0e02187fa7b8e9dae27ab65579349875bf15 Mon Sep 17 00:00:00 2001 From: Joseph Schuchart Date: Mon, 6 Nov 2017 18:52:32 +0900 Subject: [PATCH 04/24] Fix constness of GlobAtomicAsyncRef --- dash/include/dash/atomic/GlobAtomicAsyncRef.h | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/dash/include/dash/atomic/GlobAtomicAsyncRef.h b/dash/include/dash/atomic/GlobAtomicAsyncRef.h index edb162614..e4093f35d 100644 --- a/dash/include/dash/atomic/GlobAtomicAsyncRef.h +++ b/dash/include/dash/atomic/GlobAtomicAsyncRef.h @@ -135,7 +135,7 @@ class GlobAsyncRef> } /// atomically assigns value - GlobRef operator=(const T & value) const { + GlobRef operator=(const T & value) { store(value); return *this; } @@ -144,7 +144,7 @@ class GlobAsyncRef> * Set the value of the shared atomic variable. * The operation will block until the local memory can be re-used. */ - void set(const T & value) const + void set(const T & value) { DASH_LOG_DEBUG_VAR("GlobAsyncRef.set()", value); DASH_LOG_TRACE_VAR("GlobAsyncRef.set", _gptr); @@ -163,7 +163,7 @@ class GlobAsyncRef> * The operation will return immediately and the memory pointed to * by \c ptr should not be re-used before the operation has been completed. */ - void set(const T * ptr) const + void set(const T * ptr) { DASH_LOG_DEBUG_VAR("GlobAsyncRef.set()", *ptr); DASH_LOG_TRACE_VAR("GlobAsyncRef.set", _gptr); @@ -182,7 +182,7 @@ class GlobAsyncRef> * Set the value of the shared atomic variable. * The operation will block until the local memory can be re-used. */ - inline void store(const T & value) const { + inline void store(const T & value) { set(value); } @@ -191,7 +191,7 @@ class GlobAsyncRef> * The operation will return immediately and the memory pointed to * by \c ptr should not be re-used before the operation has been completed. */ - inline void store(const T * ptr) const { + inline void store(const T * ptr) { set(ptr); } @@ -257,7 +257,7 @@ class GlobAsyncRef> void op( BinaryOp binary_op, /// Value to be added to global atomic variable. - const T & value) const + const T & value) { DASH_LOG_DEBUG_VAR("GlobAsyncRef.op()", value); DASH_LOG_TRACE_VAR("GlobAsyncRef.op", _gptr); @@ -282,7 +282,7 @@ class GlobAsyncRef> BinaryOp binary_op, /// Value to be added to global atomic variable. const T & value, - T * result) const + T * result) { DASH_LOG_DEBUG_VAR("GlobAsyncRef.fetch_op()", value); DASH_LOG_TRACE_VAR("GlobAsyncRef.fetch_op", _gptr); @@ -301,7 +301,7 @@ class GlobAsyncRef> */ void exchange( const T & value, - T * result) const { + T * result) { fetch_op(dash::second(), value, result); } @@ -319,7 +319,7 @@ class GlobAsyncRef> void compare_exchange( const T & expected, const T & desired, - T * result) const { + T * result) { DASH_LOG_DEBUG_VAR("GlobAsyncRef.compare_exchange()", desired); DASH_LOG_TRACE_VAR("GlobAsyncRef.compare_exchange", _gptr); DASH_LOG_TRACE_VAR("GlobAsyncRef.compare_exchange", expected); @@ -338,7 +338,7 @@ class GlobAsyncRef> * DASH specific variant which is faster than \c fetch_add * but does not return value. */ - void add(const T & value) const + void add(const T & value) { op(dash::plus(), value); } @@ -355,7 +355,7 @@ class GlobAsyncRef> /// Value to be added to global atomic variable. const T & value, /// Pointer to store result to - T * result) const + T * result) { fetch_op(dash::plus(), value, result); } @@ -364,7 +364,7 @@ class GlobAsyncRef> * DASH specific variant which is faster than \c fetch_sub * but does not return value. */ - void sub(const T & value) const + void sub(const T & value) { op(dash::plus(), -value); } @@ -381,7 +381,7 @@ class GlobAsyncRef> /// Value to be subtracted from global atomic variable. const T & value, /// Pointer to store result to - T * result) const + T * result) { fetch_op(dash::plus(), -value, result); } From 387fcf55ddcdb660964d27afd0e57e8d9ed0894d Mon Sep 17 00:00:00 2001 From: Joseph Schuchart Date: Mon, 6 Nov 2017 18:53:56 +0900 Subject: [PATCH 05/24] GlobAsyncRef: remove postfix operators and fix operators and constness --- dash/include/dash/atomic/GlobAtomicRef.h | 58 +++++++++++------------- dash/include/dash/atomic/Operation.h | 26 +++++------ 2 files changed, 39 insertions(+), 45 deletions(-) diff --git a/dash/include/dash/atomic/GlobAtomicRef.h b/dash/include/dash/atomic/GlobAtomicRef.h index 70c8eb3fb..fcef2a818 100644 --- a/dash/include/dash/atomic/GlobAtomicRef.h +++ b/dash/include/dash/atomic/GlobAtomicRef.h @@ -16,7 +16,7 @@ template class Shared; /** - * Specialization for atomic values. All atomic operations are + * Specialization for atomic values. All atomic operations are * \c const as the \c GlobRef does not own the atomic values. */ template @@ -138,7 +138,7 @@ class GlobRef> } /// atomically assigns value - GlobRef operator=(const T & value) const { + GlobRef operator=(const T & value) { store(value); return *this; } @@ -146,7 +146,7 @@ class GlobRef> /** * Set the value of the shared atomic variable. */ - void set(const T & value) const + void set(const T & value) { DASH_LOG_DEBUG_VAR("GlobRef.store()", value); DASH_LOG_TRACE_VAR("GlobRef.store", _gptr); @@ -164,8 +164,8 @@ class GlobRef> /** * Set the value of the shared atomic variable. */ - inline void store(const T & value) const { - exchange(value); + inline void store(const T & value) { + set(value); } /// atomically fetches value @@ -201,7 +201,7 @@ class GlobRef> void op( BinaryOp binary_op, /// Value to be added to global atomic variable. - const T & value) const + const T & value) { DASH_LOG_DEBUG_VAR("GlobRef.op()", value); DASH_LOG_TRACE_VAR("GlobRef.op", _gptr); @@ -228,7 +228,7 @@ class GlobRef> T fetch_op( BinaryOp binary_op, /// Value to be added to global atomic variable. - const T & value) const + const T & value) { DASH_LOG_DEBUG_VAR("GlobRef.fetch_op()", value); DASH_LOG_TRACE_VAR("GlobRef.fetch_op", _gptr); @@ -249,19 +249,19 @@ class GlobRef> /** * Atomically exchanges value */ - T exchange(const T & value) const { + T exchange(const T & value) { return fetch_op(dash::second(), value); } /** * Atomically compares the value with the value of expected and if thosei * are bitwise-equal, replaces the former with desired. - * + * * \return True if value is exchanged - * + * * \see \c dash::atomic::compare_exchange */ - bool compare_exchange(const T & expected, const T & desired) const { + bool compare_exchange(const T & expected, const T & desired) { DASH_LOG_DEBUG_VAR("GlobRef.compare_exchange()", desired); DASH_LOG_TRACE_VAR("GlobRef.compare_exchange", _gptr); DASH_LOG_TRACE_VAR("GlobRef.compare_exchange", expected); @@ -285,7 +285,7 @@ class GlobRef> * DASH specific variant which is faster than \c fetch_add * but does not return value */ - void add(const T & value) const + void add(const T & value) { op(dash::plus(), value); } @@ -298,7 +298,7 @@ class GlobRef> */ T fetch_add( /// Value to be added to global atomic variable. - const T & value) const + const T & value) { return fetch_op(dash::plus(), value); } @@ -307,7 +307,7 @@ class GlobRef> * DASH specific variant which is faster than \c fetch_sub * but does not return value */ - void sub(const T & value) const + void sub(const T & value) { op(dash::plus(), -value); } @@ -326,33 +326,27 @@ class GlobRef> } /// prefix atomically increment value by one - T operator++ () const { - return fetch_add(1) + 1; - } - - /// postfix atomically increment value by one - T operator++ (int) const { - return fetch_add(1); + self_t& operator++ () { + add(1); + return *this; } /// prefix atomically decrement value by one - T operator-- () const { - return fetch_sub(1) - 1; - } - - /// postfix atomically decrement value by one - T operator-- (int) const { - return fetch_sub(1); + self_t& operator-- () { + sub(1); + return *this; } /// atomically increment value by ref - T operator+=(const T & value) const { - return fetch_add(value) + value; + self_t& operator+=(const T & value) { + add(value); + return *this; } /// atomically decrement value by ref - T operator-=(const T & value) const { - return fetch_sub(value) - value; + self_t& operator-=(const T & value) { + sub(value); + return *this; } }; diff --git a/dash/include/dash/atomic/Operation.h b/dash/include/dash/atomic/Operation.h index 43827c664..91685612f 100644 --- a/dash/include/dash/atomic/Operation.h +++ b/dash/include/dash/atomic/Operation.h @@ -31,15 +31,15 @@ namespace atomic { * Get the value of the shared atomic. */ template -T load(const dash::GlobRef> & ref){ +T load(const dash::GlobRef>& ref){ return ref.load(); } /** - * Set the value of the atomic reference + * Set the value of the atomic reference */ template -void store(const dash::GlobRef> & ref, +void store(dash::GlobRef> ref, const T & value) { ref.store(value); @@ -50,7 +50,7 @@ void store(const dash::GlobRef> & ref, * the old value */ template -T exchange(const dash::GlobRef> & ref, +T exchange(dash::GlobRef> ref, const T & value) { return ref.exchange(value); @@ -59,12 +59,12 @@ T exchange(const dash::GlobRef> & ref, /** * Atomically compares the value with the value of expected and if those are * bitwise-equal, replaces the former with desired. - * + * * \return True if value is exchanged */ template bool compare_exchange( - const dash::GlobRef> & ref, + dash::GlobRef> ref, const T & expected, const T & desired) { @@ -78,7 +78,7 @@ template< typename T, typename BinaryOp > void op( - const dash::GlobRef> & ref, + dash::GlobRef> ref, const BinaryOp binary_op, /// Value to be added to global atomic variable. const T & value) @@ -96,7 +96,7 @@ template< typename T, typename BinaryOp > T fetch_op( - const dash::GlobRef> & ref, + dash::GlobRef> ref, const BinaryOp binary_op, /// Value to be added to global atomic variable. const T & value) @@ -112,7 +112,7 @@ typename std::enable_if< std::is_integral::value, void>::type add( - const dash::GlobRef> & ref, + dash::GlobRef> ref, const T & value) { ref.add(value); @@ -126,7 +126,7 @@ typename std::enable_if< std::is_integral::value, void>::type sub( - const dash::GlobRef> & ref, + dash::GlobRef> ref, const T & value) { ref.sub(value); @@ -143,7 +143,7 @@ typename std::enable_if< std::is_integral::value, T>::type fetch_add( - const dash::GlobRef> & ref, + dash::GlobRef> ref, /// Value to be added to global atomic variable. const T & value) { @@ -161,13 +161,13 @@ typename std::enable_if< std::is_integral::value, T>::type fetch_sub( - const dash::GlobRef> & ref, + dash::GlobRef> ref, /// Value to be subtracted from global atomic variable. const T & value) { return ref.fetch_sub(value); } - + } // namespace atomic } // namespace dash From 5212f65ac9637be6357932939d1c8997d2364999 Mon Sep 17 00:00:00 2001 From: Joseph Schuchart Date: Mon, 6 Nov 2017 18:54:38 +0900 Subject: [PATCH 06/24] Add test for double prefix-increment in GlobAtomicRef --- dash/test/types/AtomicTest.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dash/test/types/AtomicTest.cc b/dash/test/types/AtomicTest.cc index 0ee8c78d1..296194cca 100644 --- a/dash/test/types/AtomicTest.cc +++ b/dash/test/types/AtomicTest.cc @@ -383,21 +383,21 @@ TEST_F(AtomicTest, AtomicInterface){ dash::barrier(); ++(array[0]); - array[1]++; + ++(++(array[1])); --(array[2]); - array[3]--; + --(--(array[3])); dash::barrier(); ASSERT_EQ_U(array[0].load(), dash::size()); - ASSERT_EQ_U(array[1].load(), dash::size()); + ASSERT_EQ_U(array[1].load(), 2*dash::size()); ASSERT_EQ_U(array[2].load(), -dash::size()); - ASSERT_EQ_U(array[3].load(), -dash::size()); + ASSERT_EQ_U(array[3].load(), -2*dash::size()); dash::barrier(); if(dash::myid() == 0){ auto oldval = array[3].exchange(1); - ASSERT_EQ_U(oldval, -dash::size()); + ASSERT_EQ_U(oldval, -2*dash::size()); } dash::barrier(); ASSERT_EQ_U(array[3].load(), 1); From a0d1dc9f23dc0b8567bb8a563e06c595b0f17a91 Mon Sep 17 00:00:00 2001 From: Joseph Schuchart Date: Mon, 6 Nov 2017 19:14:20 +0900 Subject: [PATCH 07/24] Add atomic multiply --- dash/include/dash/atomic/GlobAtomicAsyncRef.h | 26 +++++++++++++++++++ dash/include/dash/atomic/GlobAtomicRef.h | 22 ++++++++++++++++ dash/include/dash/atomic/Operation.h | 15 +++++++++++ dash/test/types/AtomicTest.cc | 11 ++++++++ 4 files changed, 74 insertions(+) diff --git a/dash/include/dash/atomic/GlobAtomicAsyncRef.h b/dash/include/dash/atomic/GlobAtomicAsyncRef.h index e4093f35d..03bc70682 100644 --- a/dash/include/dash/atomic/GlobAtomicAsyncRef.h +++ b/dash/include/dash/atomic/GlobAtomicAsyncRef.h @@ -386,6 +386,32 @@ class GlobAsyncRef> fetch_op(dash::plus(), -value, result); } + /** + * DASH specific variant which is faster than \c fetch_mul + * but does not return value. + */ + void multiply(const T & value) + { + op(dash::multiply(), value); + } + + /** + * Atomic fetch-and-multiply operation on the referenced shared value. + * + * The value before the operation will be stored into the memory location + * pointed to by \c result. + * + * The operation will be completed after a call to \ref flush. + */ + void fetch_multiply ( + /// Value to be subtracted from global atomic variable. + const T & value, + /// Pointer to store result to + T * result) + { + fetch_op(dash::multiply(), value, result); + } + /** * Flush all pending asynchronous operations on this asynchronous reference. */ diff --git a/dash/include/dash/atomic/GlobAtomicRef.h b/dash/include/dash/atomic/GlobAtomicRef.h index fcef2a818..26888e9b2 100644 --- a/dash/include/dash/atomic/GlobAtomicRef.h +++ b/dash/include/dash/atomic/GlobAtomicRef.h @@ -325,6 +325,28 @@ class GlobRef> return fetch_op(dash::plus(), -value); } + /** + * DASH specific variant which is faster than \c fetch_multiply + * but does not return value + */ + void multiply(const T & value) + { + op(dash::multiply(), value); + } + + /** + * Atomic fetch-and-multiply operation on the referenced shared value. + * + * \return The value of the referenced shared variable before the + * operation. + */ + T fetch_multiply( + /// Value to be added to global atomic variable. + const T & value) + { + return fetch_op(dash::multiply(), value); + } + /// prefix atomically increment value by one self_t& operator++ () { add(1); diff --git a/dash/include/dash/atomic/Operation.h b/dash/include/dash/atomic/Operation.h index 91685612f..e459498f4 100644 --- a/dash/include/dash/atomic/Operation.h +++ b/dash/include/dash/atomic/Operation.h @@ -132,6 +132,21 @@ sub( ref.sub(value); } +/** + * Atomic multiply operation on the referenced shared value. + */ +template +typename std::enable_if< + std::is_integral::value, + void>::type +multiply( + dash::GlobRef> ref, + const T & value) +{ + ref.multiply(value); +} + + /** * Atomic fetch-and-add operation on the referenced shared value. * diff --git a/dash/test/types/AtomicTest.cc b/dash/test/types/AtomicTest.cc index 296194cca..8c6214cea 100644 --- a/dash/test/types/AtomicTest.cc +++ b/dash/test/types/AtomicTest.cc @@ -579,5 +579,16 @@ TEST_F(AtomicTest, AsyncAtomic){ } dash::barrier(); + dash::fill(array.begin(), array.end(), 1); + dash::barrier(); + + if (dash::myid() == 0) { + for (size_t i = 0; i < dash::size(); ++i) { + array.async[i].multiply(2); + } + } + array.barrier(); + ASSERT_EQ_U(2, array[dash::myid()].get()); + array.barrier(); } From 8df35cb4cd3ba8010b1785684fe98d69247d53b2 Mon Sep 17 00:00:00 2001 From: Joseph Schuchart Date: Mon, 6 Nov 2017 23:14:58 +0900 Subject: [PATCH 08/24] Add test for GlobAtomicRef.multiply --- dash/test/types/AtomicTest.cc | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/dash/test/types/AtomicTest.cc b/dash/test/types/AtomicTest.cc index 8c6214cea..e4612242f 100644 --- a/dash/test/types/AtomicTest.cc +++ b/dash/test/types/AtomicTest.cc @@ -327,12 +327,33 @@ TEST_F(AtomicTest, AlgorithmVariant){ for(int i=0; i((dash::size()*(i+1)))); + } dash::barrier(); + for(int i=0; i((dash::size()*(i)))); + } + dash::barrier(); + for(int i=0; i((dash::size()*(i+1)))); + ASSERT_EQ_U( + elem_arr_local, + static_cast((dash::size()*i*(std::pow(-1, dash::size())))) + ); } } @@ -418,6 +439,9 @@ TEST_F(AtomicTest, AtomicInterface){ array.barrier(); ASSERT_EQ_U(-myid, array[myid].load()); array.barrier(); + array[1].multiply(-1); + array.barrier(); + ASSERT_EQ_U(std::pow(-1, dash::size()+1), array[1].get()); bool ret = array[myid].compare_exchange(0,10); if(myid == 0){ ASSERT_EQ_U(true, ret); From c8462e27ad6878a5bb9bee44de79dcbeafe9fa6a Mon Sep 17 00:00:00 2001 From: Joseph Schuchart Date: Tue, 7 Nov 2017 00:09:10 +0900 Subject: [PATCH 09/24] Fix atomic test for one unit --- dash/test/types/AtomicTest.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dash/test/types/AtomicTest.cc b/dash/test/types/AtomicTest.cc index e4612242f..cf6318a8e 100644 --- a/dash/test/types/AtomicTest.cc +++ b/dash/test/types/AtomicTest.cc @@ -397,8 +397,9 @@ TEST_F(AtomicTest, AtomicInterface){ using value_t = int; using atom_t = dash::Atomic; using array_t = dash::Array; + size_t num_elem = std::max(static_cast(10), dash::size()); - array_t array(10); + array_t array(num_elem); dash::fill(array.begin(), array.end(), 0); dash::barrier(); @@ -436,6 +437,7 @@ TEST_F(AtomicTest, AtomicInterface){ ASSERT_EQ_U(id_right+2, array[id_right].fetch_op(dash::plus(), 1)); array.barrier(); array[myid].exchange(-myid); + array[1].exchange(-1); array.barrier(); ASSERT_EQ_U(-myid, array[myid].load()); array.barrier(); From 04268afbe6140e34a379bbde1cfaf430f4d81cd0 Mon Sep 17 00:00:00 2001 From: Joseph Schuchart Date: Tue, 7 Nov 2017 10:56:02 +0900 Subject: [PATCH 10/24] The return of postfix increment/decrement to GlobAtomicRef --- dash/include/dash/atomic/GlobAtomicRef.h | 12 +++++++++++- dash/test/types/AtomicTest.cc | 10 ++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/dash/include/dash/atomic/GlobAtomicRef.h b/dash/include/dash/atomic/GlobAtomicRef.h index 26888e9b2..fff9f9faf 100644 --- a/dash/include/dash/atomic/GlobAtomicRef.h +++ b/dash/include/dash/atomic/GlobAtomicRef.h @@ -320,7 +320,7 @@ class GlobRef> */ T fetch_sub ( /// Value to be subtracted from global atomic variable. - const T & value) const + const T & value) { return fetch_op(dash::plus(), -value); } @@ -353,12 +353,22 @@ class GlobRef> return *this; } + /// postfix atomically increment value by one + T operator++ (int) { + return fetch_add(1); + } + /// prefix atomically decrement value by one self_t& operator-- () { sub(1); return *this; } + /// postfix atomically decrement value by one + T operator-- (int) { + return fetch_sub(1); + } + /// atomically increment value by ref self_t& operator+=(const T & value) { add(value); diff --git a/dash/test/types/AtomicTest.cc b/dash/test/types/AtomicTest.cc index cf6318a8e..e86d5b43c 100644 --- a/dash/test/types/AtomicTest.cc +++ b/dash/test/types/AtomicTest.cc @@ -415,6 +415,16 @@ TEST_F(AtomicTest, AtomicInterface){ ASSERT_EQ_U(array[2].load(), -dash::size()); ASSERT_EQ_U(array[3].load(), -2*dash::size()); + dash::barrier(); + if (dash::myid() == dash::size()-1){ + value_t prev = array[0]++; + ASSERT_EQ_U(prev, dash::size()); + ASSERT_EQ_U(array[0].load(), dash::size()+1); + + prev = array[0]--; + ASSERT_EQ_U(prev, dash::size()+1); + ASSERT_EQ_U(array[0].load(), dash::size()); + } dash::barrier(); if(dash::myid() == 0){ From a560d444201f061f67648060977bcb8a416d0c17 Mon Sep 17 00:00:00 2001 From: Joseph Schuchart Date: Wed, 8 Nov 2017 10:44:54 +0900 Subject: [PATCH 11/24] Restore behavior of GlobAtomicRef operator++()/operator--() --- dash/include/dash/atomic/GlobAtomicRef.h | 50 ++++++++++++++++-------- dash/test/types/AtomicTest.cc | 10 ++--- 2 files changed, 36 insertions(+), 24 deletions(-) diff --git a/dash/include/dash/atomic/GlobAtomicRef.h b/dash/include/dash/atomic/GlobAtomicRef.h index fff9f9faf..789a61cf7 100644 --- a/dash/include/dash/atomic/GlobAtomicRef.h +++ b/dash/include/dash/atomic/GlobAtomicRef.h @@ -347,38 +347,54 @@ class GlobRef> return fetch_op(dash::multiply(), value); } - /// prefix atomically increment value by one - self_t& operator++ () { - add(1); - return *this; + /** + * prefix atomically increment value by one + * Note that this operator does not return a reference but a copy of the value + * in order to ensure atomicity. This is consistent with the C++ std::atomic + * \c operator++, see + * http://en.cppreference.com/w/cpp/atomic/atomic/operator_arith. + */ + T operator++ () { + return fetch_add(1) + 1; } - /// postfix atomically increment value by one + /** + * postfix atomically increment value by one + */ T operator++ (int) { return fetch_add(1); } - /// prefix atomically decrement value by one - self_t& operator-- () { - sub(1); - return *this; + /** + * prefix atomically decrement value by one + * Note that this operator does not return a reference but a copy of the value + * in order to ensure atomicity. This is consistent with the C++ std::atomic + * \c operator++, see + * http://en.cppreference.com/w/cpp/atomic/atomic/operator_arith. + */ + T operator-- () { + return fetch_sub(1) + 1; } - /// postfix atomically decrement value by one + /** + * postfix atomically decrement value by one + */ T operator-- (int) { return fetch_sub(1); } - /// atomically increment value by ref - self_t& operator+=(const T & value) { - add(value); - return *this; + /** + * atomically increment value by ref + */ + T operator+=(const T & value) { + return fetch_add(value) + value; } - /// atomically decrement value by ref + /** + * atomically decrement value by ref + */ self_t& operator-=(const T & value) { - sub(value); - return *this; + return fetch_sub(value) - value; } }; diff --git a/dash/test/types/AtomicTest.cc b/dash/test/types/AtomicTest.cc index e86d5b43c..ebcf1484e 100644 --- a/dash/test/types/AtomicTest.cc +++ b/dash/test/types/AtomicTest.cc @@ -405,15 +405,11 @@ TEST_F(AtomicTest, AtomicInterface){ dash::barrier(); ++(array[0]); - ++(++(array[1])); - --(array[2]); - --(--(array[3])); + --(array[3]); dash::barrier(); ASSERT_EQ_U(array[0].load(), dash::size()); - ASSERT_EQ_U(array[1].load(), 2*dash::size()); - ASSERT_EQ_U(array[2].load(), -dash::size()); - ASSERT_EQ_U(array[3].load(), -2*dash::size()); + ASSERT_EQ_U(array[3].load(), -dash::size()); dash::barrier(); if (dash::myid() == dash::size()-1){ @@ -429,7 +425,7 @@ TEST_F(AtomicTest, AtomicInterface){ if(dash::myid() == 0){ auto oldval = array[3].exchange(1); - ASSERT_EQ_U(oldval, -2*dash::size()); + ASSERT_EQ_U(oldval, -dash::size()); } dash::barrier(); ASSERT_EQ_U(array[3].load(), 1); From 4dfe1855256973091aab37773a8838cfc1dfa6d7 Mon Sep 17 00:00:00 2001 From: Joseph Schuchart Date: Wed, 8 Nov 2017 10:57:35 +0900 Subject: [PATCH 12/24] GlobAtomicRef: delete default and copy constructor and allow move constructor (similar to GlobRef) --- dash/include/dash/atomic/GlobAtomicRef.h | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/dash/include/dash/atomic/GlobAtomicRef.h b/dash/include/dash/atomic/GlobAtomicRef.h index 789a61cf7..bef68d29a 100644 --- a/dash/include/dash/atomic/GlobAtomicRef.h +++ b/dash/include/dash/atomic/GlobAtomicRef.h @@ -52,12 +52,9 @@ class GlobRef> public: /** - * Default constructor, creates an GlobRef object referencing an element in - * global memory. + * Reference semantics forbid declaration without definition. */ - GlobRef() - : _gptr(DART_GPTR_NULL) { - } + GlobRef() = delete; /** * Constructor, creates an GlobRef object referencing an element in global @@ -92,13 +89,17 @@ class GlobRef> } /** - * Copy constructor. + * Like native references, global reference types cannot be copied. + * + * Default definition of copy constructor would conflict with semantics + * of \c operator=(const self_t &). */ - GlobRef( - /// GlobRef instance to copy. - const GlobRef & other) - : _gptr(other._gptr) - { } + GlobRef(const self_t & other) = delete; + + /** + * Unlike native reference types, global reference types are moveable. + */ + GlobRef(self_t && other) = default; self_t & operator=(const self_t & other) = delete; From 336a66a0d1d1aedabc3d083492b91571b4b37c9d Mon Sep 17 00:00:00 2001 From: Joseph Schuchart Date: Wed, 8 Nov 2017 11:04:14 +0900 Subject: [PATCH 13/24] GlobAtomicRef: use dash::internal::is_internal instead of creating a temporary GlobPtr --- dash/include/dash/atomic/GlobAtomicRef.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dash/include/dash/atomic/GlobAtomicRef.h b/dash/include/dash/atomic/GlobAtomicRef.h index bef68d29a..8b3cf0e4b 100644 --- a/dash/include/dash/atomic/GlobAtomicRef.h +++ b/dash/include/dash/atomic/GlobAtomicRef.h @@ -135,7 +135,7 @@ class GlobRef> * the calling unit's local memory. */ bool is_local() const { - return GlobPtr(_gptr).is_local(); + return dash::internal::is_local(_gptr); } /// atomically assigns value From a5f82d79dbfea544d0cb4b364d8ad8a17245c43a Mon Sep 17 00:00:00 2001 From: Joseph Schuchart Date: Wed, 8 Nov 2017 11:10:45 +0900 Subject: [PATCH 14/24] GlobAtomicAsyncRef: delete default and copy ctor and default move ctor --- dash/include/dash/atomic/GlobAtomicAsyncRef.h | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/dash/include/dash/atomic/GlobAtomicAsyncRef.h b/dash/include/dash/atomic/GlobAtomicAsyncRef.h index 03bc70682..3beb7d7cc 100644 --- a/dash/include/dash/atomic/GlobAtomicAsyncRef.h +++ b/dash/include/dash/atomic/GlobAtomicAsyncRef.h @@ -53,12 +53,9 @@ class GlobAsyncRef> public: /** - * Default constructor, creates an GlobRef object referencing an element in - * global memory. + * Reference semantics forbid declaration without definition. */ - GlobAsyncRef() - : _gptr(DART_GPTR_NULL) { - } + GlobAsyncRef() = delete; /** * Constructor, creates an GlobRef object referencing an element in global @@ -93,13 +90,17 @@ class GlobAsyncRef> } /** - * Copy constructor. + * Like native references, global reference types cannot be copied. + * + * Default definition of copy constructor would conflict with semantics + * of \c operator=(const self_t &). */ - GlobAsyncRef( - /// GlobRef instance to copy. - const GlobAsyncRef & other) - : _gptr(other._gptr) - { } + GlobAsyncRef(const self_t & other) = delete; + + /** + * Unlike native reference types, global reference types are moveable. + */ + GlobAsyncRef(self_t && other) = default; self_t & operator=(const self_t & other) = delete; From 3c2d74930247561e48294eb54fbd0b49499c2d7b Mon Sep 17 00:00:00 2001 From: Joseph Schuchart Date: Wed, 8 Nov 2017 16:46:31 +0900 Subject: [PATCH 15/24] GlobAtomicRef: Fix comment --- dash/include/dash/atomic/GlobAtomicRef.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dash/include/dash/atomic/GlobAtomicRef.h b/dash/include/dash/atomic/GlobAtomicRef.h index 8b3cf0e4b..312bc0197 100644 --- a/dash/include/dash/atomic/GlobAtomicRef.h +++ b/dash/include/dash/atomic/GlobAtomicRef.h @@ -370,7 +370,7 @@ class GlobRef> * prefix atomically decrement value by one * Note that this operator does not return a reference but a copy of the value * in order to ensure atomicity. This is consistent with the C++ std::atomic - * \c operator++, see + * \c operator--, see * http://en.cppreference.com/w/cpp/atomic/atomic/operator_arith. */ T operator-- () { From 56093e6508c96c1779910ad2975a0c0b94c1ad2c Mon Sep 17 00:00:00 2001 From: Joseph Schuchart Date: Wed, 8 Nov 2017 17:10:58 +0900 Subject: [PATCH 16/24] Fix operator-= and add test coverage --- dash/include/dash/atomic/GlobAtomicRef.h | 12 +++++++++++- dash/test/types/AtomicTest.cc | 4 ++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/dash/include/dash/atomic/GlobAtomicRef.h b/dash/include/dash/atomic/GlobAtomicRef.h index 312bc0197..c8804ef49 100644 --- a/dash/include/dash/atomic/GlobAtomicRef.h +++ b/dash/include/dash/atomic/GlobAtomicRef.h @@ -386,6 +386,11 @@ class GlobRef> /** * atomically increment value by ref + * + * Note that this operator does not return a reference but a copy of the value + * in order to ensure atomicity. This is consistent with the C++ std::atomic + * \c operator+=, see + * http://en.cppreference.com/w/cpp/atomic/atomic/operator_arith2. */ T operator+=(const T & value) { return fetch_add(value) + value; @@ -393,8 +398,13 @@ class GlobRef> /** * atomically decrement value by ref + * + * Note that this operator does not return a reference but a copy of the value + * in order to ensure atomicity. This is consistent with the C++ std::atomic + * \c operator-=, see + * http://en.cppreference.com/w/cpp/atomic/atomic/operator_arith2. */ - self_t& operator-=(const T & value) { + T operator-=(const T & value) { return fetch_sub(value) - value; } diff --git a/dash/test/types/AtomicTest.cc b/dash/test/types/AtomicTest.cc index ebcf1484e..a8c6ee45c 100644 --- a/dash/test/types/AtomicTest.cc +++ b/dash/test/types/AtomicTest.cc @@ -458,6 +458,10 @@ TEST_F(AtomicTest, AtomicInterface){ ASSERT_EQ_U(false, ret); } array.barrier(); + array[0] += 1; + array[0] -= 1; + array.barrier(); + ASSERT_EQ_U(10, array[0].get()); } TEST_F(AtomicTest, MutexInterface){ From 88e0f7e04925fa57e0dbb430b706b02c4328d9c1 Mon Sep 17 00:00:00 2001 From: Joseph Schuchart Date: Wed, 8 Nov 2017 17:30:02 +0900 Subject: [PATCH 17/24] Fix comments and operator= in atomic references --- dash/include/dash/atomic/GlobAtomicAsyncRef.h | 36 ++++++++------- dash/include/dash/atomic/GlobAtomicRef.h | 44 +++++++++++++++---- 2 files changed, 56 insertions(+), 24 deletions(-) diff --git a/dash/include/dash/atomic/GlobAtomicAsyncRef.h b/dash/include/dash/atomic/GlobAtomicAsyncRef.h index 3beb7d7cc..a4d06599a 100644 --- a/dash/include/dash/atomic/GlobAtomicAsyncRef.h +++ b/dash/include/dash/atomic/GlobAtomicAsyncRef.h @@ -13,9 +13,6 @@ namespace dash { template class Atomic; -template -class Shared; - /** * Specialization for atomic values. All atomic operations are * \c const as the \c GlobRef does not own the atomic values. @@ -86,7 +83,7 @@ class GlobAsyncRef> explicit GlobAsyncRef(dart_gptr_t dart_gptr) : _gptr(dart_gptr) { - DASH_LOG_TRACE_VAR("GlobRef(dart_gptr_t)", dart_gptr); + DASH_LOG_TRACE_VAR("GlobAsyncRef(dart_gptr_t)", dart_gptr); } /** @@ -118,8 +115,8 @@ class GlobAsyncRef> inline bool operator!=(const T & value) const = delete; operator GlobPtr() const { - DASH_LOG_TRACE("GlobRef.GlobPtr()", "conversion operator"); - DASH_LOG_TRACE_VAR("GlobRef.T()", _gptr); + DASH_LOG_TRACE("GlobAsyncRef.GlobPtr()", "conversion operator"); + DASH_LOG_TRACE_VAR("GlobAsyncRef.T()", _gptr); return GlobPtr(_gptr); } @@ -135,10 +132,19 @@ class GlobAsyncRef> return GlobPtr(_gptr).is_local(); } - /// atomically assigns value - GlobRef operator=(const T & value) { + /** + * atomically assigns value + * + * \return The assigned value. + * + * \note This operator does not return a reference but a copy of the value + * in order to ensure atomicity. This is consistent with the C++ std::atomic + * \c operator=, see + * http://en.cppreference.com/w/cpp/atomic/atomic/operator%3D. + */ + T operator=(const T & value) { store(value); - return *this; + return value; } /** @@ -204,8 +210,8 @@ class GlobAsyncRef> */ T get() const { - DASH_LOG_DEBUG("GlobRef.get()"); - DASH_LOG_TRACE_VAR("GlobRef.get", _gptr); + DASH_LOG_DEBUG("GlobAsyncRef.get()"); + DASH_LOG_TRACE_VAR("GlobAsyncRef.get", _gptr); value_type nothing; value_type result; dart_ret_t ret = dart_fetch_and_op( @@ -216,7 +222,7 @@ class GlobAsyncRef> DART_OP_NO_OP); dart_flush_local(_gptr); DASH_ASSERT_EQ(DART_OK, ret, "dart_accumulate failed"); - DASH_LOG_DEBUG_VAR("GlobRef.get >", result); + DASH_LOG_DEBUG_VAR("GlobAsyncRef.get >", result); return result; } @@ -229,8 +235,8 @@ class GlobAsyncRef> */ void get(T * result) const { - DASH_LOG_DEBUG("GlobRef.get()"); - DASH_LOG_TRACE_VAR("GlobRef.get", _gptr); + DASH_LOG_DEBUG("GlobAsyncRef.get()"); + DASH_LOG_TRACE_VAR("GlobAsyncRef.get", _gptr); value_type nothing; dart_ret_t ret = dart_fetch_and_op( _gptr, @@ -325,7 +331,7 @@ class GlobAsyncRef> DASH_LOG_TRACE_VAR("GlobAsyncRef.compare_exchange", _gptr); DASH_LOG_TRACE_VAR("GlobAsyncRef.compare_exchange", expected); DASH_LOG_TRACE_VAR( - "GlobRef.compare_exchange", typeid(desired).name()); + "GlobAsyncRef.compare_exchange", typeid(desired).name()); dart_ret_t ret = dart_compare_and_swap( _gptr, reinterpret_cast(&desired), diff --git a/dash/include/dash/atomic/GlobAtomicRef.h b/dash/include/dash/atomic/GlobAtomicRef.h index c8804ef49..00786b253 100644 --- a/dash/include/dash/atomic/GlobAtomicRef.h +++ b/dash/include/dash/atomic/GlobAtomicRef.h @@ -12,9 +12,6 @@ namespace dash { template class Atomic; -template -class Shared; - /** * Specialization for atomic values. All atomic operations are * \c const as the \c GlobRef does not own the atomic values. @@ -138,10 +135,19 @@ class GlobRef> return dash::internal::is_local(_gptr); } - /// atomically assigns value - GlobRef operator=(const T & value) { + /** + * atomically assigns value + * + * \return The assigned value. + * + * \note This operator does not return a reference but a copy of the value + * in order to ensure atomicity. This is consistent with the C++ std::atomic + * \c operator=, see + * http://en.cppreference.com/w/cpp/atomic/atomic/operator%3D. + */ + T operator=(const T & value) { store(value); - return *this; + return value; } /** @@ -350,7 +356,11 @@ class GlobRef> /** * prefix atomically increment value by one - * Note that this operator does not return a reference but a copy of the value + * + * \return The value of the referenced shared variable after the + * operation. + * + * \note This operator does not return a reference but a copy of the value * in order to ensure atomicity. This is consistent with the C++ std::atomic * \c operator++, see * http://en.cppreference.com/w/cpp/atomic/atomic/operator_arith. @@ -361,6 +371,9 @@ class GlobRef> /** * postfix atomically increment value by one + * + * \return The value of the referenced shared variable before the + * operation. */ T operator++ (int) { return fetch_add(1); @@ -368,7 +381,11 @@ class GlobRef> /** * prefix atomically decrement value by one - * Note that this operator does not return a reference but a copy of the value + * + * \return The value of the referenced shared variable after the + * operation. + * + * \note This operator does not return a reference but a copy of the value * in order to ensure atomicity. This is consistent with the C++ std::atomic * \c operator--, see * http://en.cppreference.com/w/cpp/atomic/atomic/operator_arith. @@ -379,6 +396,9 @@ class GlobRef> /** * postfix atomically decrement value by one + * + * \return The value of the referenced shared variable before the + * operation. */ T operator-- (int) { return fetch_sub(1); @@ -387,7 +407,10 @@ class GlobRef> /** * atomically increment value by ref * - * Note that this operator does not return a reference but a copy of the value + * \return The value of the referenced shared variable after the + * operation. + * + * \note This operator does not return a reference but a copy of the value * in order to ensure atomicity. This is consistent with the C++ std::atomic * \c operator+=, see * http://en.cppreference.com/w/cpp/atomic/atomic/operator_arith2. @@ -399,6 +422,9 @@ class GlobRef> /** * atomically decrement value by ref * + * \return The value of the referenced shared variable after the + * operation. + * * Note that this operator does not return a reference but a copy of the value * in order to ensure atomicity. This is consistent with the C++ std::atomic * \c operator-=, see From 63e471abc50a2d6e5304f02bd487794fa042d2b4 Mon Sep 17 00:00:00 2001 From: Joseph Schuchart Date: Thu, 9 Nov 2017 09:44:03 +0900 Subject: [PATCH 18/24] Use universal references in atomic operations --- dash/include/dash/atomic/Operation.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/dash/include/dash/atomic/Operation.h b/dash/include/dash/atomic/Operation.h index e459498f4..cbfff1407 100644 --- a/dash/include/dash/atomic/Operation.h +++ b/dash/include/dash/atomic/Operation.h @@ -39,7 +39,7 @@ T load(const dash::GlobRef>& ref){ * Set the value of the atomic reference */ template -void store(dash::GlobRef> ref, +void store(dash::GlobRef>&& ref, const T & value) { ref.store(value); @@ -50,7 +50,7 @@ void store(dash::GlobRef> ref, * the old value */ template -T exchange(dash::GlobRef> ref, +T exchange(dash::GlobRef>&& ref, const T & value) { return ref.exchange(value); @@ -64,7 +64,7 @@ T exchange(dash::GlobRef> ref, */ template bool compare_exchange( - dash::GlobRef> ref, + dash::GlobRef>&& ref, const T & expected, const T & desired) { @@ -78,7 +78,7 @@ template< typename T, typename BinaryOp > void op( - dash::GlobRef> ref, + dash::GlobRef>&& ref, const BinaryOp binary_op, /// Value to be added to global atomic variable. const T & value) @@ -96,7 +96,7 @@ template< typename T, typename BinaryOp > T fetch_op( - dash::GlobRef> ref, + dash::GlobRef>&& ref, const BinaryOp binary_op, /// Value to be added to global atomic variable. const T & value) @@ -112,7 +112,7 @@ typename std::enable_if< std::is_integral::value, void>::type add( - dash::GlobRef> ref, + dash::GlobRef>&& ref, const T & value) { ref.add(value); @@ -126,7 +126,7 @@ typename std::enable_if< std::is_integral::value, void>::type sub( - dash::GlobRef> ref, + dash::GlobRef>&& ref, const T & value) { ref.sub(value); @@ -140,7 +140,7 @@ typename std::enable_if< std::is_integral::value, void>::type multiply( - dash::GlobRef> ref, + dash::GlobRef>&& ref, const T & value) { ref.multiply(value); @@ -158,7 +158,7 @@ typename std::enable_if< std::is_integral::value, T>::type fetch_add( - dash::GlobRef> ref, + dash::GlobRef>&& ref, /// Value to be added to global atomic variable. const T & value) { @@ -176,7 +176,7 @@ typename std::enable_if< std::is_integral::value, T>::type fetch_sub( - dash::GlobRef> ref, + dash::GlobRef>&& ref, /// Value to be subtracted from global atomic variable. const T & value) { From 8ef3690c549521c55e5b0a5be11fa2b9639171ca Mon Sep 17 00:00:00 2001 From: Joseph Schuchart Date: Fri, 10 Nov 2017 13:13:58 +0900 Subject: [PATCH 19/24] Fix const correctness for GlobRef using GlobRef --- dash/include/dash/Array.h | 4 +- dash/include/dash/GlobRef.h | 132 +++++++++++++----- dash/include/dash/Matrix.h | 4 +- dash/include/dash/atomic/GlobAtomicRef.h | 93 ++++++++---- dash/include/dash/atomic/Operation.h | 20 +-- .../include/dash/matrix/internal/Matrix-inl.h | 4 +- .../dash/matrix/internal/MatrixRef-inl.h | 18 +-- 7 files changed, 186 insertions(+), 89 deletions(-) diff --git a/dash/include/dash/Array.h b/dash/include/dash/Array.h index 1c9813ca9..c2c9f48bf 100644 --- a/dash/include/dash/Array.h +++ b/dash/include/dash/Array.h @@ -660,8 +660,8 @@ class Array typedef std::reverse_iterator< iterator> reverse_iterator; typedef std::reverse_iterator const_reverse_iterator; - typedef GlobRef< value_type> reference; - typedef GlobRef const_reference; + typedef GlobRef reference; + typedef typename GlobRef::const_type const_reference; typedef GlobIter< value_type, PatternType> pointer; typedef GlobIter const_pointer; diff --git a/dash/include/dash/GlobRef.h b/dash/include/dash/GlobRef.h index 8a5f0283b..e05131bfb 100644 --- a/dash/include/dash/GlobRef.h +++ b/dash/include/dash/GlobRef.h @@ -26,6 +26,18 @@ struct has_subscript_operator static bool const value = sizeof(check(0)) == sizeof(yes); }; +template +struct match_const +{ + using type = TargetT; +}; + +template +struct match_const +{ + using type = typename std::add_const::type; +}; + template class GlobRef { @@ -38,21 +50,13 @@ class GlobRef typename ElementT > friend class GlobRef; - typedef typename std::remove_const::type - nonconst_value_type; - - typedef typename std::add_const::type - const_value_type; public: - typedef T value_type; + using value_type = T; + using const_value_type = typename std::add_const::type; + using nonconst_value_type = typename std::remove_const::type; + using self_t = GlobRef; + using const_type = GlobRef; - typedef GlobRef const_type; - -private: - typedef GlobRef - self_t; - typedef GlobRef - self_const_t; private: dart_gptr_t _gptr; @@ -114,7 +118,7 @@ class GlobRef explicit constexpr GlobRef(dart_gptr_t dart_gptr) : _gptr(dart_gptr) { } - + /** * Constructor to convert \c GlobAsyncRef to GlobRef. Set to explicit to * avoid unintendet conversion @@ -131,7 +135,7 @@ class GlobRef * of \c operator=(const self_t &). */ GlobRef(const self_t & other) = delete; - + /** * Unlike native reference types, global reference types are moveable. */ @@ -140,7 +144,7 @@ class GlobRef /** * Value-assignment operator. */ - self_t & operator=(const T val) { + const self_t & operator=(const value_type& val) const { set(val); return *this; } @@ -148,7 +152,7 @@ class GlobRef /** * Assignment operator. */ - self_t & operator=(const self_t & other) + const self_t & operator=(const self_t & other) const { set(static_cast(other)); return *this; @@ -158,7 +162,7 @@ class GlobRef * Assignment operator. */ template - self_t & operator=(GlobRefOrElementT && other) + const self_t & operator=(GlobRefOrElementT && other) const { set(std::forward(other)); return *this; @@ -199,7 +203,26 @@ class GlobRef return !(*this == value); } - void set(const_value_type & val) { + /** + * Implicit cast to const. + */ + operator GlobRef () const { + return GlobRef(_gptr); + } + + /** + * Explicit cast to non-const + */ + explicit + operator GlobRef () const { + return GlobRef(_gptr); + } + + void + set(const value_type & val) const { + static_assert(std::is_same::value, + "Cannot modify value referenced by GlobRef!"); + DASH_LOG_TRACE_VAR("GlobRef.set()", val); DASH_LOG_TRACE_VAR("GlobRef.set", _gptr); // TODO: Clarify if dart-call can be avoided if @@ -245,7 +268,10 @@ class GlobRef ); } - void put(const_value_type& tref) { + void + put(const_value_type& tref) const { + static_assert(std::is_same::value, + "Cannot assign to GlobRef!"); DASH_LOG_TRACE("GlobRef.put(T&)", "explicit put of provided ref"); DASH_LOG_TRACE_VAR("GlobRef.T()", _gptr); dash::dart_storage ds(1); @@ -256,7 +282,10 @@ class GlobRef ); } - void put(const_value_type* tptr) { + void + put(const_value_type* tptr) const { + static_assert(std::is_same::value, + "Cannot modify value referenced by GlobRef!"); DASH_LOG_TRACE("GlobRef.put(T*)", "explicit put of provided ptr"); DASH_LOG_TRACE_VAR("GlobRef.T()", _gptr); dash::dart_storage ds(1); @@ -267,7 +296,10 @@ class GlobRef ); } - self_t & operator+=(const nonconst_value_type& ref) { + const self_t & + operator+=(const nonconst_value_type& ref) const { + static_assert(std::is_same::value, + "Cannot modify value referenced by GlobRef!"); #if 0 // TODO: Alternative implementation, possibly more efficient: T add_val = ref; @@ -288,56 +320,80 @@ class GlobRef return *this; } - self_t & operator-=(const nonconst_value_type& ref) { + const self_t & + operator-=(const nonconst_value_type& ref) const { + static_assert(std::is_same::value, + "Cannot modify value referenced by GlobRef!"); nonconst_value_type val = operator nonconst_value_type(); val -= ref; operator=(val); return *this; } - self_t & operator++() { + const self_t & + operator++() const { + static_assert(std::is_same::value, + "Cannot modify value referenced by GlobRef!"); nonconst_value_type val = operator nonconst_value_type(); ++val; operator=(val); return *this; } - nonconst_value_type operator++(int) { + nonconst_value_type + operator++(int) const { + static_assert(std::is_same::value, + "Cannot modify value referenced by GlobRef!"); nonconst_value_type val = operator nonconst_value_type(); nonconst_value_type result = val++; operator=(val); return result; } - self_t & operator--() { + const self_t & + operator--() const { + static_assert(std::is_same::value, + "Cannot modify value referenced by GlobRef!"); nonconst_value_type val = operator nonconst_value_type(); --val; operator=(val); return *this; } - nonconst_value_type operator--(int) { + nonconst_value_type + operator--(int) const { + static_assert(std::is_same::value, + "Cannot modify value referenced by GlobRef!"); nonconst_value_type val = operator nonconst_value_type(); nonconst_value_type result = val--; operator=(val); return result; } - self_t & operator*=(const_value_type& ref) { + const self_t & + operator*=(const_value_type& ref) const { + static_assert(std::is_same::value, + "Cannot modify value referenced by GlobRef!"); nonconst_value_type val = operator nonconst_value_type(); val *= ref; operator=(val); return *this; } - self_t & operator/=(const_value_type& ref) { + const self_t & + operator/=(const_value_type& ref) const { + static_assert(std::is_same::value, + "Cannot modify value referenced by GlobRef!"); nonconst_value_type val = operator nonconst_value_type(); val /= ref; operator=(val); return *this; } - self_t & operator^=(const_value_type& ref) { + const self_t & + operator^=(const_value_type& ref) const { + static_assert(std::is_same::value, + "Cannot modify value referenced by GlobRef!"); nonconst_value_type val = operator nonconst_value_type(); val ^= ref; operator=(val); @@ -376,29 +432,33 @@ class GlobRef * specified offset */ template - GlobRef member(size_t offs) const { + GlobRef::type> + member(size_t offs) const { dart_gptr_t dartptr = _gptr; DASH_ASSERT_RETURNS( dart_gptr_incaddr(&dartptr, offs), DART_OK); - return GlobRef(dartptr); + return GlobRef::type>(dartptr); } /** * Get the member via pointer to member */ template - GlobRef member( + GlobRef::type> + member( const MEMTYPE P::*mem) const { // TODO: Thaaaat ... looks hacky. size_t offs = (size_t) &( reinterpret_cast(0)->*mem); - return member(offs); + return member::type>(offs); } /** - * specialization which swappes the values of two global references + * specialization which swappes the values of two global references */ - inline void swap(dash::GlobRef & b){ + inline void swap(dash::GlobRef & b) const{ + static_assert(std::is_same::value, + "Cannot modify value referenced by GlobRef!"); T tmp = static_cast(*this); *this = b; b = tmp; diff --git a/dash/include/dash/Matrix.h b/dash/include/dash/Matrix.h index 992b09ba6..de8901aa1 100644 --- a/dash/include/dash/Matrix.h +++ b/dash/include/dash/Matrix.h @@ -185,8 +185,8 @@ class Matrix typedef std::reverse_iterator reverse_iterator; typedef std::reverse_iterator const_reverse_iterator; - typedef GlobRef< value_type> reference; - typedef GlobRef const_reference; + typedef GlobRef reference; + typedef typename GlobRef::const_type const_reference; typedef GlobIter< value_type, Pattern_t> pointer; typedef GlobIter const_pointer; diff --git a/dash/include/dash/atomic/GlobAtomicRef.h b/dash/include/dash/atomic/GlobAtomicRef.h index 00786b253..4b1cac773 100644 --- a/dash/include/dash/atomic/GlobAtomicRef.h +++ b/dash/include/dash/atomic/GlobAtomicRef.h @@ -35,14 +35,15 @@ class GlobRef> const GlobRef & gref); public: - typedef T - value_type; - typedef GlobRef> - const_type; - -private: - typedef dash::Atomic atomic_t; - typedef GlobRef self_t; + using value_type = T; + using const_value_type = typename std::add_const::type; + using nonconst_value_type = typename std::remove_const::type; + using atomic_t = dash::Atomic; + using const_atomic_t = typename dash::Atomic; + using nonconst_atomic_t = typename dash::Atomic; + using self_t = GlobRef; + using const_type = GlobRef; + using nonconst_type = GlobRef>; private: dart_gptr_t _gptr; @@ -71,10 +72,18 @@ class GlobRef> template GlobRef( /// Pointer to referenced object in global memory - const GlobPtr & gptr) + const GlobPtr & gptr) : GlobRef(gptr.dart_gptr()) { } + template + GlobRef( + /// Pointer to referenced object in global memory + const GlobPtr & gptr) + : GlobRef(gptr.dart_gptr()) + { } + + /** * Constructor, creates an GlobRef object referencing an element in global * memory. @@ -123,6 +132,22 @@ class GlobRef> return GlobPtr(_gptr); } + /** + * Implicit conversion to const type. + */ + operator const_type() const { + return const_type(_gptr); + } + + /** + * Implicit conversion to const type. + */ + explicit + operator nonconst_type() const { + return nonconst_type(_gptr); + } + + dart_gptr_t dart_gptr() const { return _gptr; } @@ -145,7 +170,7 @@ class GlobRef> * \c operator=, see * http://en.cppreference.com/w/cpp/atomic/atomic/operator%3D. */ - T operator=(const T & value) { + T operator=(const T & value) const { store(value); return value; } @@ -153,8 +178,10 @@ class GlobRef> /** * Set the value of the shared atomic variable. */ - void set(const T & value) + void set(const T & value) const { + static_assert(std::is_same::value, + "Cannot modify value referenced by GlobRef>!"); DASH_LOG_DEBUG_VAR("GlobRef.store()", value); DASH_LOG_TRACE_VAR("GlobRef.store", _gptr); dart_ret_t ret = dart_accumulate( @@ -171,7 +198,7 @@ class GlobRef> /** * Set the value of the shared atomic variable. */ - inline void store(const T & value) { + inline void store(const T & value) const { set(value); } @@ -208,8 +235,10 @@ class GlobRef> void op( BinaryOp binary_op, /// Value to be added to global atomic variable. - const T & value) + const T & value) const { + static_assert(std::is_same::value, + "Cannot modify value referenced by GlobRef>!"); DASH_LOG_DEBUG_VAR("GlobRef.op()", value); DASH_LOG_TRACE_VAR("GlobRef.op", _gptr); value_type acc = value; @@ -235,8 +264,10 @@ class GlobRef> T fetch_op( BinaryOp binary_op, /// Value to be added to global atomic variable. - const T & value) + const T & value) const { + static_assert(std::is_same::value, + "Cannot modify value referenced by GlobRef>!"); DASH_LOG_DEBUG_VAR("GlobRef.fetch_op()", value); DASH_LOG_TRACE_VAR("GlobRef.fetch_op", _gptr); DASH_LOG_TRACE_VAR("GlobRef.fetch_op", typeid(value).name()); @@ -256,7 +287,7 @@ class GlobRef> /** * Atomically exchanges value */ - T exchange(const T & value) { + T exchange(const T & value) const { return fetch_op(dash::second(), value); } @@ -268,7 +299,9 @@ class GlobRef> * * \see \c dash::atomic::compare_exchange */ - bool compare_exchange(const T & expected, const T & desired) { + bool compare_exchange(const T & expected, const T & desired) const { + static_assert(std::is_same::value, + "Cannot modify value referenced by GlobRef!"); DASH_LOG_DEBUG_VAR("GlobRef.compare_exchange()", desired); DASH_LOG_TRACE_VAR("GlobRef.compare_exchange", _gptr); DASH_LOG_TRACE_VAR("GlobRef.compare_exchange", expected); @@ -292,8 +325,10 @@ class GlobRef> * DASH specific variant which is faster than \c fetch_add * but does not return value */ - void add(const T & value) + void add(const T & value) const { + static_assert(std::is_same::value, + "Cannot modify value referenced by GlobRef!"); op(dash::plus(), value); } @@ -303,9 +338,9 @@ class GlobRef> * \return The value of the referenced shared variable before the * operation. */ - T fetch_add( + T fetch_add ( /// Value to be added to global atomic variable. - const T & value) + const T & value) const { return fetch_op(dash::plus(), value); } @@ -314,7 +349,7 @@ class GlobRef> * DASH specific variant which is faster than \c fetch_sub * but does not return value */ - void sub(const T & value) + void sub(const T & value) const { op(dash::plus(), -value); } @@ -327,7 +362,7 @@ class GlobRef> */ T fetch_sub ( /// Value to be subtracted from global atomic variable. - const T & value) + const T & value) const { return fetch_op(dash::plus(), -value); } @@ -336,7 +371,7 @@ class GlobRef> * DASH specific variant which is faster than \c fetch_multiply * but does not return value */ - void multiply(const T & value) + void multiply(const T & value) const { op(dash::multiply(), value); } @@ -349,7 +384,7 @@ class GlobRef> */ T fetch_multiply( /// Value to be added to global atomic variable. - const T & value) + const T & value) const { return fetch_op(dash::multiply(), value); } @@ -365,7 +400,7 @@ class GlobRef> * \c operator++, see * http://en.cppreference.com/w/cpp/atomic/atomic/operator_arith. */ - T operator++ () { + T operator++ () const { return fetch_add(1) + 1; } @@ -375,7 +410,7 @@ class GlobRef> * \return The value of the referenced shared variable before the * operation. */ - T operator++ (int) { + T operator++ (int) const { return fetch_add(1); } @@ -390,7 +425,7 @@ class GlobRef> * \c operator--, see * http://en.cppreference.com/w/cpp/atomic/atomic/operator_arith. */ - T operator-- () { + T operator-- () const { return fetch_sub(1) + 1; } @@ -400,7 +435,7 @@ class GlobRef> * \return The value of the referenced shared variable before the * operation. */ - T operator-- (int) { + T operator-- (int) const { return fetch_sub(1); } @@ -415,7 +450,7 @@ class GlobRef> * \c operator+=, see * http://en.cppreference.com/w/cpp/atomic/atomic/operator_arith2. */ - T operator+=(const T & value) { + T operator+=(const T & value) const { return fetch_add(value) + value; } @@ -430,7 +465,7 @@ class GlobRef> * \c operator-=, see * http://en.cppreference.com/w/cpp/atomic/atomic/operator_arith2. */ - T operator-=(const T & value) { + T operator-=(const T & value) const { return fetch_sub(value) - value; } diff --git a/dash/include/dash/atomic/Operation.h b/dash/include/dash/atomic/Operation.h index cbfff1407..1f083feb1 100644 --- a/dash/include/dash/atomic/Operation.h +++ b/dash/include/dash/atomic/Operation.h @@ -39,7 +39,7 @@ T load(const dash::GlobRef>& ref){ * Set the value of the atomic reference */ template -void store(dash::GlobRef>&& ref, +void store(const dash::GlobRef>& ref, const T & value) { ref.store(value); @@ -50,7 +50,7 @@ void store(dash::GlobRef>&& ref, * the old value */ template -T exchange(dash::GlobRef>&& ref, +T exchange(const dash::GlobRef>& ref, const T & value) { return ref.exchange(value); @@ -64,7 +64,7 @@ T exchange(dash::GlobRef>&& ref, */ template bool compare_exchange( - dash::GlobRef>&& ref, + const dash::GlobRef>& ref, const T & expected, const T & desired) { @@ -78,7 +78,7 @@ template< typename T, typename BinaryOp > void op( - dash::GlobRef>&& ref, + const dash::GlobRef>& ref, const BinaryOp binary_op, /// Value to be added to global atomic variable. const T & value) @@ -96,7 +96,7 @@ template< typename T, typename BinaryOp > T fetch_op( - dash::GlobRef>&& ref, + const dash::GlobRef>& ref, const BinaryOp binary_op, /// Value to be added to global atomic variable. const T & value) @@ -112,7 +112,7 @@ typename std::enable_if< std::is_integral::value, void>::type add( - dash::GlobRef>&& ref, + const dash::GlobRef>& ref, const T & value) { ref.add(value); @@ -126,7 +126,7 @@ typename std::enable_if< std::is_integral::value, void>::type sub( - dash::GlobRef>&& ref, + const dash::GlobRef>& ref, const T & value) { ref.sub(value); @@ -140,7 +140,7 @@ typename std::enable_if< std::is_integral::value, void>::type multiply( - dash::GlobRef>&& ref, + const dash::GlobRef>& ref, const T & value) { ref.multiply(value); @@ -158,7 +158,7 @@ typename std::enable_if< std::is_integral::value, T>::type fetch_add( - dash::GlobRef>&& ref, + const dash::GlobRef>& ref, /// Value to be added to global atomic variable. const T & value) { @@ -176,7 +176,7 @@ typename std::enable_if< std::is_integral::value, T>::type fetch_sub( - dash::GlobRef>&& ref, + const dash::GlobRef>& ref, /// Value to be subtracted from global atomic variable. const T & value) { diff --git a/dash/include/dash/matrix/internal/Matrix-inl.h b/dash/include/dash/matrix/internal/Matrix-inl.h index a197c0aa9..96d1922c6 100644 --- a/dash/include/dash/matrix/internal/Matrix-inl.h +++ b/dash/include/dash/matrix/internal/Matrix-inl.h @@ -464,7 +464,7 @@ constexpr Matrix::operator[](size_type pos) const template template typename std::enable_if<(__NumViewDim == 0), - GlobRef>::type + typename Matrix::const_reference>::type constexpr Matrix::operator[](size_type pos) const { return _ref.at(pos); @@ -483,7 +483,7 @@ ::operator[](size_type pos) template template typename std::enable_if<(__NumViewDim == 0), - GlobRef>::type + typename Matrix::reference>::type Matrix::operator[](size_type pos) { return _ref.at(pos); diff --git a/dash/include/dash/matrix/internal/MatrixRef-inl.h b/dash/include/dash/matrix/internal/MatrixRef-inl.h index 8641835ac..04f83dd3e 100644 --- a/dash/include/dash/matrix/internal/MatrixRef-inl.h +++ b/dash/include/dash/matrix/internal/MatrixRef-inl.h @@ -54,7 +54,7 @@ MatrixRef ::team() const noexcept { return *(_refview._mat->_team); -} +} template constexpr typename MatrixRef::size_type @@ -62,8 +62,8 @@ MatrixRef ::size() const noexcept { return _refview._viewspec.size(); -} - +} + template typename MatrixRef::size_type constexpr MatrixRef @@ -286,7 +286,7 @@ ::lend() noexcept template template -typename std::enable_if<(__NumViewDim != 0), +typename std::enable_if<(__NumViewDim != 0), MatrixRef>::type MatrixRef ::operator[]( @@ -297,7 +297,7 @@ ::operator[]( template template -typename std::enable_if<(__NumViewDim != 0), +typename std::enable_if<(__NumViewDim != 0), MatrixRef>::type constexpr MatrixRef ::operator[](size_type pos) const { @@ -306,7 +306,8 @@ ::operator[](size_type pos) const { template template -typename std::enable_if<(__NumViewDim == 0), GlobRef >::type +typename std::enable_if<(__NumViewDim == 0), + typename MatrixRef::reference >::type MatrixRef ::operator[](size_type pos) { @@ -317,7 +318,8 @@ ::operator[](size_type pos) template template -typename std::enable_if<(__NumViewDim == 0), GlobRef >::type +typename std::enable_if<(__NumViewDim == 0), + typename MatrixRef::const_reference >::type MatrixRef ::operator[](size_type pos) const { @@ -337,7 +339,7 @@ ::sub( MatrixRef * >(this)->sub(offset); } - + template template MatrixRef From eeb338056789fdb0bc1fd82ddf759c36399739df Mon Sep 17 00:00:00 2001 From: Joseph Schuchart Date: Fri, 10 Nov 2017 13:25:23 +0900 Subject: [PATCH 20/24] GlobAtomicRef: Add static_assert to ctor --- dash/include/dash/atomic/GlobAtomicRef.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/dash/include/dash/atomic/GlobAtomicRef.h b/dash/include/dash/atomic/GlobAtomicRef.h index 4b1cac773..432d8fd46 100644 --- a/dash/include/dash/atomic/GlobAtomicRef.h +++ b/dash/include/dash/atomic/GlobAtomicRef.h @@ -74,7 +74,10 @@ class GlobRef> /// Pointer to referenced object in global memory const GlobPtr & gptr) : GlobRef(gptr.dart_gptr()) - { } + { + static_assert(std::is_same::value, + "Cannot create GlobRef> from GlobPtr!"); + } template GlobRef( @@ -222,7 +225,7 @@ class GlobRef> } /** - * Set the value of the shared atomic variable. + * Get the value of the shared atomic variable. */ inline T load() const { return get(); @@ -233,8 +236,9 @@ class GlobRef> */ template void op( + /// Binary operation to be performed on global atomic variable BinaryOp binary_op, - /// Value to be added to global atomic variable. + /// Value to be used in binary op on global atomic variable. const T & value) const { static_assert(std::is_same::value, From d9fcc1fa44450b40cd860ce02fa90c9c535a694d Mon Sep 17 00:00:00 2001 From: Joseph Schuchart Date: Fri, 10 Nov 2017 15:30:11 +0900 Subject: [PATCH 21/24] Make GlobAsyncRef and GlobAtomicAsyncRef const-aware --- dash/include/dash/Array.h | 6 +- dash/include/dash/GlobAsyncRef.h | 90 ++++++++++----- dash/include/dash/GlobRef.h | 20 +--- dash/include/dash/Types.h | 5 + dash/include/dash/atomic/GlobAtomicAsyncRef.h | 103 +++++++++++------- dash/include/dash/atomic/GlobAtomicRef.h | 24 ++-- 6 files changed, 148 insertions(+), 100 deletions(-) diff --git a/dash/include/dash/Array.h b/dash/include/dash/Array.h index c2c9f48bf..e0e142b3f 100644 --- a/dash/include/dash/Array.h +++ b/dash/include/dash/Array.h @@ -286,8 +286,8 @@ class AsyncArrayRef typedef T * pointer; typedef const T * const_pointer; - typedef GlobAsyncRef< T> async_reference; - typedef GlobAsyncRef const_async_reference; + typedef GlobAsyncRef async_reference; + typedef typename GlobAsyncRef::const_type const_async_reference; public: typedef std::integral_constant @@ -363,7 +363,7 @@ class AsyncArrayRef * Subscript operator, access to local array element at given position. */ constexpr const_async_reference operator[](const size_type n) const { - return async_reference( + return const_async_reference( (*(_array->begin() + n)).dart_gptr()); } diff --git a/dash/include/dash/GlobAsyncRef.h b/dash/include/dash/GlobAsyncRef.h index e56325750..e8dfedf6c 100644 --- a/dash/include/dash/GlobAsyncRef.h +++ b/dash/include/dash/GlobAsyncRef.h @@ -9,6 +9,20 @@ namespace dash { + +template +struct add_const_from_type +{ + using type = TargetT; +}; + +template +struct add_const_from_type +{ + using type = typename std::add_const::type; +}; + + /** * Global value reference for asynchronous / non-blocking operations. * @@ -45,23 +59,22 @@ class GlobAsyncRef typename ElementT > friend class GlobAsyncRef; -private: - typedef GlobAsyncRef - self_t; - - typedef typename std::remove_const::type - nonconst_value_type; +public: + using value_type = T; + using const_value_type = typename std::add_const::type; + using nonconst_value_type = typename std::remove_const::type; + using self_t = GlobAsyncRef; + using const_type = GlobAsyncRef; + using nonconst_type = GlobAsyncRef; - typedef typename std::add_const::type - const_value_type; private: /// Pointer to referenced element in global memory dart_gptr_t _gptr; /// Temporary value required for non-blocking put - nonconst_value_type _value; + mutable nonconst_value_type _value; /// DART handle for asynchronous transfers - dart_handle_t _handle = DART_HANDLE_NULL; + mutable dart_handle_t _handle = DART_HANDLE_NULL; private: @@ -105,14 +118,13 @@ class GlobAsyncRef { } /** - * Constructor, creates an GlobRef object referencing an element in global - * memory. + * Conctructor, creates an GlobRefAsync object referencing an element in + * global memory. */ - template explicit GlobAsyncRef( /// Pointer to referenced object in global memory - const GlobConstPtr & gptr) - : GlobAsyncRef(gptr.dart_gptr()) + const GlobRef & gref) + : GlobAsyncRef(gref.dart_gptr()) { } /** @@ -121,9 +133,27 @@ class GlobAsyncRef */ explicit GlobAsyncRef( /// Pointer to referenced object in global memory - const GlobRef & gref) + const GlobRef & gref) : GlobAsyncRef(gref.dart_gptr()) - { } + { + static_assert(std::is_same::value, + "Cannot create GlobAsyncRef from GlobRef!"); + } + + /** + * Implicit conversion to const. + */ + operator GlobAsyncRef() { + return GlobAsyncRef(_gptr); + } + + /** + * Excpliti conversion to non-const. + */ + explicit + operator GlobAsyncRef() { + return GlobAsyncRef(_gptr); + } /** * Like native references, global reference types cannot be copied. @@ -157,24 +187,28 @@ class GlobAsyncRef * specified offset */ template - GlobAsyncRef member(size_t offs) const { - return GlobAsyncRef(*this, offs); + GlobAsyncRef::type> + member(size_t offs) const { + return GlobAsyncRef::type>(*this, offs); } /** * Get the member via pointer to member */ template - GlobAsyncRef member( + GlobAsyncRef::type> + member( const MEMTYPE P::*mem) const { size_t offs = (size_t) &( reinterpret_cast(0)->*mem); - return member(offs); + return member::type>(offs); } /** * Swap values with synchronous reads and asynchronous writes. */ friend void swap(self_t & a, self_t & b) { + static_assert(std::is_same::value, + "Cannot swap GlobAsyncRef!"); nonconst_value_type temp = a->get(); a = b->get(); b = temp; @@ -225,7 +259,9 @@ class GlobAsyncRef * This operation is guaranteed to be complete after a call to \ref flush * and the pointer \c tptr should not be reused before completion. */ - void set(const_value_type* tptr) { + void set(const_value_type* tptr) const { + static_assert(std::is_same::value, + "Cannot modify value through GlobAsyncRef!"); DASH_LOG_TRACE_VAR("GlobAsyncRef.set()", *tptr); DASH_LOG_TRACE_VAR("GlobAsyncRef.set()", _gptr); dash::dart_storage ds(1); @@ -241,7 +277,9 @@ class GlobAsyncRef * This operation is guaranteed to be complete after a call to \ref flush, * but the value referenced by \c new_value can be re-used immediately. */ - void set(const_value_type& new_value) { + void set(const_value_type& new_value) const { + static_assert(std::is_same::value, + "Cannot modify value through GlobAsyncRef!"); DASH_LOG_TRACE_VAR("GlobAsyncRef.set()", new_value); DASH_LOG_TRACE_VAR("GlobAsyncRef.set()", _gptr); dash::dart_storage ds(1); @@ -265,8 +303,8 @@ class GlobAsyncRef * This operation is guaranteed to be complete after a call to \ref flush, * but the value referenced by \c new_value can be re-used immediately. */ - self_t & - operator=(const_value_type & new_value) + const self_t & + operator=(const_value_type & new_value) const { set(new_value); return *this; @@ -282,7 +320,7 @@ class GlobAsyncRef /** * Flush all pending asynchronous operations on this asynchronous reference. */ - void flush() + void flush() const { DASH_ASSERT_RETURNS( dart_flush(_gptr), diff --git a/dash/include/dash/GlobRef.h b/dash/include/dash/GlobRef.h index e05131bfb..873a4cdcd 100644 --- a/dash/include/dash/GlobRef.h +++ b/dash/include/dash/GlobRef.h @@ -26,18 +26,6 @@ struct has_subscript_operator static bool const value = sizeof(check(0)) == sizeof(yes); }; -template -struct match_const -{ - using type = TargetT; -}; - -template -struct match_const -{ - using type = typename std::add_const::type; -}; - template class GlobRef { @@ -432,25 +420,25 @@ class GlobRef * specified offset */ template - GlobRef::type> + GlobRef::type> member(size_t offs) const { dart_gptr_t dartptr = _gptr; DASH_ASSERT_RETURNS( dart_gptr_incaddr(&dartptr, offs), DART_OK); - return GlobRef::type>(dartptr); + return GlobRef::type>(dartptr); } /** * Get the member via pointer to member */ template - GlobRef::type> + GlobRef::type> member( const MEMTYPE P::*mem) const { // TODO: Thaaaat ... looks hacky. size_t offs = (size_t) &( reinterpret_cast(0)->*mem); - return member::type>(offs); + return member::type>(offs); } /** diff --git a/dash/include/dash/Types.h b/dash/include/dash/Types.h index ec40f787c..cc5ac2e47 100644 --- a/dash/include/dash/Types.h +++ b/dash/include/dash/Types.h @@ -159,6 +159,11 @@ struct dart_datatype { static constexpr const dart_datatype_t value = DART_TYPE_DOUBLE; }; +template +struct dart_datatype : public dart_datatype +{ }; + + namespace internal { diff --git a/dash/include/dash/atomic/GlobAtomicAsyncRef.h b/dash/include/dash/atomic/GlobAtomicAsyncRef.h index a4d06599a..a288f8ed2 100644 --- a/dash/include/dash/atomic/GlobAtomicAsyncRef.h +++ b/dash/include/dash/atomic/GlobAtomicAsyncRef.h @@ -36,14 +36,16 @@ class GlobAsyncRef> const GlobAsyncRef & gref); public: - typedef T - value_type; - typedef GlobAsyncRef> - const_type; + using value_type = T; + using const_value_type = typename std::add_const::type; + using nonconst_value_type = typename std::remove_const::type; + using atomic_t = dash::Atomic; + using const_atomic_t = typename dash::Atomic; + using nonconst_atomic_t = typename dash::Atomic; + using self_t = GlobAsyncRef; + using const_type = GlobAsyncRef; + using nonconst_type = GlobAsyncRef>; -private: - typedef dash::Atomic atomic_t; - typedef GlobAsyncRef self_t; private: dart_gptr_t _gptr; @@ -120,6 +122,17 @@ class GlobAsyncRef> return GlobPtr(_gptr); } + operator GlobAsyncRef() + { + return GlobAsyncRef(_gptr); + } + + explicit + operator GlobAsyncRef() + { + return GlobAsyncRef(_gptr); + } + dart_gptr_t dart_gptr() const { return _gptr; } @@ -142,7 +155,7 @@ class GlobAsyncRef> * \c operator=, see * http://en.cppreference.com/w/cpp/atomic/atomic/operator%3D. */ - T operator=(const T & value) { + T operator=(const T & value) const { store(value); return value; } @@ -151,15 +164,17 @@ class GlobAsyncRef> * Set the value of the shared atomic variable. * The operation will block until the local memory can be re-used. */ - void set(const T & value) + void set(const T & value) const { + static_assert(std::is_same::value, + "Cannot modify value referenced by GlobAsyncRef>!"); DASH_LOG_DEBUG_VAR("GlobAsyncRef.set()", value); DASH_LOG_TRACE_VAR("GlobAsyncRef.set", _gptr); dart_ret_t ret = dart_accumulate_blocking_local( _gptr, reinterpret_cast(&value), 1, - dash::dart_punned_datatype::value, + dash::dart_punned_datatype::value, DART_OP_REPLACE); DASH_ASSERT_EQ(DART_OK, ret, "dart_accumulate failed"); DASH_LOG_DEBUG("GlobAsyncRef.set >"); @@ -170,15 +185,17 @@ class GlobAsyncRef> * The operation will return immediately and the memory pointed to * by \c ptr should not be re-used before the operation has been completed. */ - void set(const T * ptr) + void set(const T * ptr) const { + static_assert(std::is_same::value, + "Cannot modify value referenced by GlobAsyncRef>!"); DASH_LOG_DEBUG_VAR("GlobAsyncRef.set()", *ptr); DASH_LOG_TRACE_VAR("GlobAsyncRef.set", _gptr); dart_ret_t ret = dart_accumulate( _gptr, reinterpret_cast(ptr), 1, - dash::dart_punned_datatype::value, + dash::dart_punned_datatype::value, DART_OP_REPLACE); DASH_ASSERT_EQ(DART_OK, ret, "dart_accumulate failed"); DASH_LOG_DEBUG("GlobAsyncRef.set >"); @@ -189,7 +206,7 @@ class GlobAsyncRef> * Set the value of the shared atomic variable. * The operation will block until the local memory can be re-used. */ - inline void store(const T & value) { + inline void store(const T & value) const { set(value); } @@ -198,7 +215,7 @@ class GlobAsyncRef> * The operation will return immediately and the memory pointed to * by \c ptr should not be re-used before the operation has been completed. */ - inline void store(const T * ptr) { + inline void store(const T * ptr) const { set(ptr); } @@ -212,13 +229,13 @@ class GlobAsyncRef> { DASH_LOG_DEBUG("GlobAsyncRef.get()"); DASH_LOG_TRACE_VAR("GlobAsyncRef.get", _gptr); - value_type nothing; - value_type result; + nonconst_value_type nothing; + nonconst_value_type result; dart_ret_t ret = dart_fetch_and_op( _gptr, reinterpret_cast(¬hing), reinterpret_cast(&result), - dash::dart_punned_datatype::value, + dash::dart_punned_datatype::value, DART_OP_NO_OP); dart_flush_local(_gptr); DASH_ASSERT_EQ(DART_OK, ret, "dart_accumulate failed"); @@ -237,12 +254,12 @@ class GlobAsyncRef> { DASH_LOG_DEBUG("GlobAsyncRef.get()"); DASH_LOG_TRACE_VAR("GlobAsyncRef.get", _gptr); - value_type nothing; + nonconst_value_type nothing; dart_ret_t ret = dart_fetch_and_op( _gptr, reinterpret_cast(¬hing), reinterpret_cast(result), - dash::dart_punned_datatype::value, + dash::dart_punned_datatype::value, DART_OP_NO_OP); DASH_ASSERT_EQ(DART_OK, ret, "dart_accumulate failed"); } @@ -264,8 +281,10 @@ class GlobAsyncRef> void op( BinaryOp binary_op, /// Value to be added to global atomic variable. - const T & value) + const T & value) const { + static_assert(std::is_same::value, + "Cannot modify value referenced by GlobAsyncRef>!"); DASH_LOG_DEBUG_VAR("GlobAsyncRef.op()", value); DASH_LOG_TRACE_VAR("GlobAsyncRef.op", _gptr); DASH_LOG_TRACE("GlobAsyncRef.op", "dart_accumulate"); @@ -273,7 +292,7 @@ class GlobAsyncRef> _gptr, reinterpret_cast(&value), 1, - dash::dart_punned_datatype::value, + dash::dart_punned_datatype::value, binary_op.dart_operation()); DASH_ASSERT_EQ(DART_OK, ret, "dart_accumulate_blocking_local failed"); } @@ -289,8 +308,10 @@ class GlobAsyncRef> BinaryOp binary_op, /// Value to be added to global atomic variable. const T & value, - T * result) + T * result) const { + static_assert(std::is_same::value, + "Cannot modify value referenced by GlobAsyncRef>!"); DASH_LOG_DEBUG_VAR("GlobAsyncRef.fetch_op()", value); DASH_LOG_TRACE_VAR("GlobAsyncRef.fetch_op", _gptr); DASH_LOG_TRACE_VAR("GlobAsyncRef.fetch_op", typeid(value).name()); @@ -298,7 +319,7 @@ class GlobAsyncRef> _gptr, reinterpret_cast(&value), reinterpret_cast(result), - dash::dart_punned_datatype::value, + dash::dart_punned_datatype::value, binary_op.dart_operation()); DASH_ASSERT_EQ(DART_OK, ret, "dart_fetch_op failed"); } @@ -308,8 +329,8 @@ class GlobAsyncRef> */ void exchange( const T & value, - T * result) { - fetch_op(dash::second(), value, result); + T * result) const { + fetch_op(dash::second(), value, result); } /** @@ -326,7 +347,9 @@ class GlobAsyncRef> void compare_exchange( const T & expected, const T & desired, - T * result) { + T * result) const { + static_assert(std::is_same::value, + "Cannot modify value referenced by GlobAsyncRef>!"); DASH_LOG_DEBUG_VAR("GlobAsyncRef.compare_exchange()", desired); DASH_LOG_TRACE_VAR("GlobAsyncRef.compare_exchange", _gptr); DASH_LOG_TRACE_VAR("GlobAsyncRef.compare_exchange", expected); @@ -337,7 +360,7 @@ class GlobAsyncRef> reinterpret_cast(&desired), reinterpret_cast(&expected), reinterpret_cast(result), - dash::dart_punned_datatype::value); + dash::dart_punned_datatype::value); DASH_ASSERT_EQ(DART_OK, ret, "dart_compare_and_swap failed"); } @@ -345,9 +368,9 @@ class GlobAsyncRef> * DASH specific variant which is faster than \c fetch_add * but does not return value. */ - void add(const T & value) + void add(const T & value) const { - op(dash::plus(), value); + op(dash::plus(), value); } /** @@ -362,18 +385,18 @@ class GlobAsyncRef> /// Value to be added to global atomic variable. const T & value, /// Pointer to store result to - T * result) + T * result) const { - fetch_op(dash::plus(), value, result); + fetch_op(dash::plus(), value, result); } /** * DASH specific variant which is faster than \c fetch_sub * but does not return value. */ - void sub(const T & value) + void sub(const T & value) const { - op(dash::plus(), -value); + op(dash::plus(), -value); } /** @@ -388,18 +411,18 @@ class GlobAsyncRef> /// Value to be subtracted from global atomic variable. const T & value, /// Pointer to store result to - T * result) + T * result) const { - fetch_op(dash::plus(), -value, result); + fetch_op(dash::plus(), -value, result); } /** * DASH specific variant which is faster than \c fetch_mul * but does not return value. */ - void multiply(const T & value) + void multiply(const T & value) const { - op(dash::multiply(), value); + op(dash::multiply(), value); } /** @@ -414,15 +437,15 @@ class GlobAsyncRef> /// Value to be subtracted from global atomic variable. const T & value, /// Pointer to store result to - T * result) + T * result) const { - fetch_op(dash::multiply(), value, result); + fetch_op(dash::multiply(), value, result); } /** * Flush all pending asynchronous operations on this asynchronous reference. */ - void flush() + void flush() const { DASH_ASSERT_RETURNS( dart_flush(_gptr), diff --git a/dash/include/dash/atomic/GlobAtomicRef.h b/dash/include/dash/atomic/GlobAtomicRef.h index 432d8fd46..1c4633798 100644 --- a/dash/include/dash/atomic/GlobAtomicRef.h +++ b/dash/include/dash/atomic/GlobAtomicRef.h @@ -76,7 +76,7 @@ class GlobRef> : GlobRef(gptr.dart_gptr()) { static_assert(std::is_same::value, - "Cannot create GlobRef> from GlobPtr!"); + "Cannot create GlobRef> from GlobPtr!"); } template @@ -129,12 +129,6 @@ class GlobRef> return load(); } - operator GlobPtr() const { - DASH_LOG_TRACE("GlobRef.GlobPtr()", "conversion operator"); - DASH_LOG_TRACE_VAR("GlobRef.T()", _gptr); - return GlobPtr(_gptr); - } - /** * Implicit conversion to const type. */ @@ -184,7 +178,7 @@ class GlobRef> void set(const T & value) const { static_assert(std::is_same::value, - "Cannot modify value referenced by GlobRef>!"); + "Cannot modify value referenced by GlobRef>!"); DASH_LOG_DEBUG_VAR("GlobRef.store()", value); DASH_LOG_TRACE_VAR("GlobRef.store", _gptr); dart_ret_t ret = dart_accumulate( @@ -210,8 +204,8 @@ class GlobRef> { DASH_LOG_DEBUG("GlobRef.load()"); DASH_LOG_TRACE_VAR("GlobRef.load", _gptr); - value_type nothing; - value_type result; + nonconst_value_type nothing; + nonconst_value_type result; dart_ret_t ret = dart_fetch_and_op( _gptr, reinterpret_cast(¬hing), @@ -242,10 +236,10 @@ class GlobRef> const T & value) const { static_assert(std::is_same::value, - "Cannot modify value referenced by GlobRef>!"); + "Cannot modify value referenced by GlobRef>!"); DASH_LOG_DEBUG_VAR("GlobRef.op()", value); DASH_LOG_TRACE_VAR("GlobRef.op", _gptr); - value_type acc = value; + nonconst_value_type acc = value; DASH_LOG_TRACE("GlobRef.op", "dart_accumulate"); dart_ret_t ret = dart_accumulate( _gptr, @@ -271,11 +265,11 @@ class GlobRef> const T & value) const { static_assert(std::is_same::value, - "Cannot modify value referenced by GlobRef>!"); + "Cannot modify value referenced by GlobRef>!"); DASH_LOG_DEBUG_VAR("GlobRef.fetch_op()", value); DASH_LOG_TRACE_VAR("GlobRef.fetch_op", _gptr); DASH_LOG_TRACE_VAR("GlobRef.fetch_op", typeid(value).name()); - value_type res; + nonconst_value_type res; dart_ret_t ret = dart_fetch_and_op( _gptr, reinterpret_cast(&value), @@ -311,7 +305,7 @@ class GlobRef> DASH_LOG_TRACE_VAR("GlobRef.compare_exchange", expected); DASH_LOG_TRACE_VAR( "GlobRef.compare_exchange", typeid(desired).name()); - value_type result; + nonconst_value_type result; dart_ret_t ret = dart_compare_and_swap( _gptr, reinterpret_cast(&desired), From 87877f61d47003e7c3954ade9fb799d9c358d24b Mon Sep 17 00:00:00 2001 From: Joseph Schuchart Date: Fri, 10 Nov 2017 16:31:51 +0900 Subject: [PATCH 22/24] Add test cases --- dash/test/iterator/GlobAsyncRefTest.cc | 42 ++++++++++++++++++++++++++ dash/test/types/AtomicTest.cc | 40 ++++++++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/dash/test/iterator/GlobAsyncRefTest.cc b/dash/test/iterator/GlobAsyncRefTest.cc index d43e74c22..5e09ec439 100644 --- a/dash/test/iterator/GlobAsyncRefTest.cc +++ b/dash/test/iterator/GlobAsyncRefTest.cc @@ -154,3 +154,45 @@ TEST_F(GlobAsyncRefTest, RefOfStruct) } } + + +TEST_F(GlobAsyncRefTest, ConstTest) +{ + + dash::Array array(dash::size()); + const dash::Array& carr = array; + array[dash::myid()].set(0); + dash::barrier(); + + // conversion non-const -> const + dash::GlobRef gref1 = array[0]; + // assignment const -> const + dash::GlobRef gref2 = carr[0]; + // explicit conversion const->non-const + dash::GlobRef gref3 = static_cast>(carr[0]); + + // should fail! + //gref1.set(0); + + // works + ASSERT_EQ_U(0, gref1.get()); + + /** + * GlobAsyncRef + */ + + // conversion non-const -> const + dash::GlobAsyncRef agref1 = array.async[0]; + // assignment const -> const + dash::GlobAsyncRef agref2 = carr.async[0]; + // explicit conversion const->non-const + dash::GlobAsyncRef agref3 = + static_cast>(carr.async[0]); + + // should fail! + //agref1.set(0); + + // works + ASSERT_EQ_U(0, agref1.get()); + +} diff --git a/dash/test/types/AtomicTest.cc b/dash/test/types/AtomicTest.cc index a8c6ee45c..cb1efb23f 100644 --- a/dash/test/types/AtomicTest.cc +++ b/dash/test/types/AtomicTest.cc @@ -628,3 +628,43 @@ TEST_F(AtomicTest, AsyncAtomic){ array.barrier(); } + +TEST_F(AtomicTest, ConstTest) { + + dash::Array> array(dash::size()); + const dash::Array>& carr = array; + array[dash::myid()].set(0); + dash::barrier(); + + // conversion non-const -> const + dash::GlobRef> gref1 = array[0]; + // assignment const -> const + dash::GlobRef> gref2 = carr[0]; + // explicit conversion const->non-const + dash::GlobRef> gref3 = + static_cast>>(carr[0]); + + // should fail! + //gref1.add(1); + + // works + ASSERT_EQ_U(0, gref1.get()); + + /** + * GlobAsyncRef + */ + + // conversion non-const -> const + dash::GlobAsyncRef> agref1 = array.async[0]; + // assignment const -> const + dash::GlobAsyncRef> agref2 = carr.async[0]; + // explicit conversion const->non-const + dash::GlobAsyncRef> agref3 = + static_cast>>(carr.async[0]); + + // should fail! + //agref1.add(1); + + // works + ASSERT_EQ_U(0, agref1.get()); +} From 087e665fea9c3fc139ec3a10378218a2d1242207 Mon Sep 17 00:00:00 2001 From: Joseph Schuchart Date: Fri, 10 Nov 2017 16:42:48 +0900 Subject: [PATCH 23/24] Remove bogus cast operator GlobAtomicAsyncRef -> GlobPtr --- dash/include/dash/atomic/GlobAtomicAsyncRef.h | 17 +++++++---------- dash/include/dash/atomic/GlobAtomicRef.h | 2 +- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/dash/include/dash/atomic/GlobAtomicAsyncRef.h b/dash/include/dash/atomic/GlobAtomicAsyncRef.h index a288f8ed2..c729d3598 100644 --- a/dash/include/dash/atomic/GlobAtomicAsyncRef.h +++ b/dash/include/dash/atomic/GlobAtomicAsyncRef.h @@ -63,7 +63,7 @@ class GlobAsyncRef> template explicit GlobAsyncRef( /// Pointer to referenced object in global memory - GlobPtr & gptr) + const GlobPtr & gptr) : GlobAsyncRef(gptr.dart_gptr()) { } @@ -72,11 +72,14 @@ class GlobAsyncRef> * memory. */ template - GlobAsyncRef( + explicit GlobAsyncRef( /// Pointer to referenced object in global memory - const GlobPtr & gptr) + const GlobPtr & gptr) : GlobAsyncRef(gptr.dart_gptr()) - { } + { + static_assert(std::is_same::value, + "Cannot create GlobAsyncRef> from GlobPtr>!"); + } /** * Constructor, creates an GlobRef object referencing an element in global @@ -116,12 +119,6 @@ class GlobAsyncRef> inline bool operator==(const T & value) const = delete; inline bool operator!=(const T & value) const = delete; - operator GlobPtr() const { - DASH_LOG_TRACE("GlobAsyncRef.GlobPtr()", "conversion operator"); - DASH_LOG_TRACE_VAR("GlobAsyncRef.T()", _gptr); - return GlobPtr(_gptr); - } - operator GlobAsyncRef() { return GlobAsyncRef(_gptr); diff --git a/dash/include/dash/atomic/GlobAtomicRef.h b/dash/include/dash/atomic/GlobAtomicRef.h index 1c4633798..6516c4850 100644 --- a/dash/include/dash/atomic/GlobAtomicRef.h +++ b/dash/include/dash/atomic/GlobAtomicRef.h @@ -76,7 +76,7 @@ class GlobRef> : GlobRef(gptr.dart_gptr()) { static_assert(std::is_same::value, - "Cannot create GlobRef> from GlobPtr!"); + "Cannot create GlobRef> from GlobPtr>!"); } template From 1ac3875dcd5f30e9cb91eb0b076ab7ee6e2f3e78 Mon Sep 17 00:00:00 2001 From: Joseph Schuchart Date: Sat, 13 Jan 2018 09:54:16 +0900 Subject: [PATCH 24/24] Fix GlobAtomicRef::operator--() --- dash/include/dash/atomic/GlobAtomicRef.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dash/include/dash/atomic/GlobAtomicRef.h b/dash/include/dash/atomic/GlobAtomicRef.h index e4530a6ca..4009d30b5 100644 --- a/dash/include/dash/atomic/GlobAtomicRef.h +++ b/dash/include/dash/atomic/GlobAtomicRef.h @@ -411,7 +411,7 @@ class GlobRef> * http://en.cppreference.com/w/cpp/atomic/atomic/operator_arith. */ T operator-- () const { - return fetch_sub(1) + 1; + return fetch_sub(1) - 1; } /**