diff --git a/dart-if/include/dash/dart/if/dart_communication.h b/dart-if/include/dash/dart/if/dart_communication.h index 23e7b96a6..6b5dfb66b 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 diff --git a/dart-impl/mpi/src/dart_communication.c b/dart-impl/mpi/src/dart_communication.c index c8a923062..538af63e3 100644 --- a/dart-impl/mpi/src/dart_communication.c +++ b/dart-impl/mpi/src/dart_communication.c @@ -589,16 +589,13 @@ dart_ret_t dart_accumulate( 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; CHECK_IS_BASICTYPE(dtype); - mpi_dtype = dart__mpi__datatype_struct(dtype)->basic.mpi_type; - mpi_op = dart__mpi__op(op); + MPI_Op mpi_op = dart__mpi__op(op); dart_team_data_t *team_data = dart_adapt_teamlist_get(teamid); @@ -651,24 +648,118 @@ dart_ret_t dart_accumulate( DART_LOG_TRACE("dart_accumulate: MPI_Accumulate (src %p, size %zu)", src_ptr, remainder); - CHECK_MPI_RET( - MPI_Accumulate( + MPI_Datatype mpi_dtype = dart__mpi__datatype_struct(dtype)->basic.mpi_type; + CHECK_MPI_RET( + MPI_Accumulate( + src_ptr, + remainder, + mpi_dtype, + team_unit_id.id, + offset, + remainder, + mpi_dtype, + mpi_op, + win), + "MPI_Accumulate"); + } + + DART_LOG_DEBUG("dart_accumulate > finished"); + 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) +{ + 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; + + CHECK_IS_BASICTYPE(dtype); + MPI_Op 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:%ld 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_Raccumulate (src %p, size %zu)", + src_ptr, nchunks * MAX_CONTIG_ELEMENTS); + CHECK_MPI_RET( + MPI_Raccumulate( src_ptr, - remainder, - mpi_dtype, + nchunks, + dart__mpi__datatype_maxtype(dtype), team_unit_id.id, offset, - remainder, - mpi_dtype, + nchunks, + dart__mpi__datatype_maxtype(dtype), mpi_op, - win), - "MPI_Accumulate"); + 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_Raccumulate (src %p, size %zu)", + src_ptr, remainder); + + MPI_Datatype mpi_dtype = dart__mpi__datatype_struct(dtype)->basic.mpi_type; + 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, diff --git a/dash/include/dash/Array.h b/dash/include/dash/Array.h index 5211ecbbd..29b602d7d 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()); } @@ -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/Atomic.h b/dash/include/dash/Atomic.h index 91941e189..98ed9724b 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 @@ -115,6 +115,7 @@ std::ostream & operator<<( #include #include +#include #include #endif // DASH__ATOMIC_H__INCLUDED diff --git a/dash/include/dash/GlobAsyncRef.h b/dash/include/dash/GlobAsyncRef.h index d80137093..7afd3de92 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. * @@ -46,24 +60,20 @@ class GlobAsyncRef friend class GlobAsyncRef; public: - typedef GlobAsyncRef - self_t; - - typedef T value_type; - - typedef typename std::remove_const::type - nonconst_value_type; - - typedef typename std::add_const::type - const_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 = GlobAsyncRef; + using const_type = GlobAsyncRef; + using nonconst_type = GlobAsyncRef; 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: @@ -107,14 +117,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()) { } /** @@ -123,9 +132,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. @@ -159,24 +186,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; @@ -219,7 +250,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::internal::put(_gptr, tptr, 1); @@ -231,7 +264,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); _value = new_value; @@ -250,8 +285,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; @@ -276,7 +311,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 2f22c03e5..c874b74c8 100644 --- a/dash/include/dash/GlobRef.h +++ b/dash/include/dash/GlobRef.h @@ -38,21 +38,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; - - typedef GlobRef 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 self_t = GlobRef; + using const_type = GlobRef; -private: - typedef GlobRef - self_t; - typedef GlobRef - self_const_t; private: dart_gptr_t _gptr; @@ -140,7 +132,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 +140,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 +150,7 @@ class GlobRef * Assignment operator. */ template - self_t & operator=(GlobRefOrElementT && other) + const self_t & operator=(GlobRefOrElementT && other) const { set(std::forward(other)); return *this; @@ -196,7 +188,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 @@ -225,19 +236,28 @@ class GlobRef dash::internal::get_blocking(_gptr, &tref, 1); } - 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::internal::put_blocking(_gptr, &tref, 1); } - 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::internal::put_blocking(_gptr, tptr, 1); } - 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; @@ -258,54 +278,78 @@ 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(); 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 res = val++; operator=(val); return res; } - 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(); 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 res = val--; operator=(val); return res; } - 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); @@ -344,29 +388,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 */ - 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 094a7c50a..444fe4877 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/Types.h b/dash/include/dash/Types.h index ce92ceabc..f49491df2 100644 --- a/dash/include/dash/Types.h +++ b/dash/include/dash/Types.h @@ -170,10 +170,10 @@ struct dart_datatype { }; template -struct dart_datatype : dart_datatype { }; +struct dart_datatype : public dart_datatype { }; template -struct dart_datatype : dart_datatype { }; +struct dart_datatype : public dart_datatype { }; namespace internal { diff --git a/dash/include/dash/atomic/GlobAtomicAsyncRef.h b/dash/include/dash/atomic/GlobAtomicAsyncRef.h new file mode 100644 index 000000000..c729d3598 --- /dev/null +++ b/dash/include/dash/atomic/GlobAtomicAsyncRef.h @@ -0,0 +1,458 @@ +#ifndef DASH__ATOMIC_ASYNC_GLOBREF_H_ +#define DASH__ATOMIC_ASYNC_GLOBREF_H_ + +#include +#include +#include +#include + + +namespace dash { + +// forward decls +template +class Atomic; + +/** + * 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: + 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: + dart_gptr_t _gptr; + +public: + /** + * Reference semantics forbid declaration without definition. + */ + GlobAsyncRef() = delete; + + /** + * Constructor, creates an GlobRef object referencing an element in global + * memory. + */ + template + explicit 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. + */ + template + explicit GlobAsyncRef( + /// Pointer to referenced object in global memory + 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 + * memory. + */ + explicit GlobAsyncRef(dart_gptr_t dart_gptr) + : _gptr(dart_gptr) + { + DASH_LOG_TRACE_VAR("GlobAsyncRef(dart_gptr_t)", dart_gptr); + } + + /** + * 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(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; + + 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 GlobAsyncRef() + { + return GlobAsyncRef(_gptr); + } + + explicit + operator GlobAsyncRef() + { + return GlobAsyncRef(_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 + * + * \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) const { + store(value); + return value; + } + + /** + * 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 + { + 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, + 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 + { + 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, + 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("GlobAsyncRef.get()"); + DASH_LOG_TRACE_VAR("GlobAsyncRef.get", _gptr); + 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, + DART_OP_NO_OP); + dart_flush_local(_gptr); + DASH_ASSERT_EQ(DART_OK, ret, "dart_accumulate failed"); + DASH_LOG_DEBUG_VAR("GlobAsyncRef.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("GlobAsyncRef.get()"); + DASH_LOG_TRACE_VAR("GlobAsyncRef.get", _gptr); + nonconst_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 + { + 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"); + 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 + { + 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()); + 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 { + 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); + DASH_LOG_TRACE_VAR( + "GlobAsyncRef.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); + } + + /** + * DASH specific variant which is faster than \c fetch_mul + * but does not return value. + */ + void multiply(const T & value) const + { + 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) const + { + fetch_op(dash::multiply(), value, result); + } + + /** + * Flush all pending asynchronous operations on this asynchronous reference. + */ + void flush() const + { + DASH_ASSERT_RETURNS( + dart_flush(_gptr), + DART_OK + ); + } + +}; + +} // namespace dash + +#endif // DASH__ATOMIC_ASYNC_GLOBREF_H_ + diff --git a/dash/include/dash/atomic/GlobAtomicRef.h b/dash/include/dash/atomic/GlobAtomicRef.h index b33f581a4..28dc49072 100644 --- a/dash/include/dash/atomic/GlobAtomicRef.h +++ b/dash/include/dash/atomic/GlobAtomicRef.h @@ -12,100 +12,126 @@ 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. - */ +* Specialization for atomic values. All atomic operations are +* \c const as the \c GlobRef does not own the atomic values. +*/ template class GlobRef> { - /* 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 GlobRef & gref); +/* 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 GlobRef & gref); public: - typedef T - value_type; - typedef GlobRef> - 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 = GlobRef; +using const_type = GlobRef; +using nonconst_type = GlobRef>; private: - typedef dash::Atomic atomic_t; - typedef GlobRef self_t; - -private: - dart_gptr_t _gptr; +dart_gptr_t _gptr; public: - /** - * Default constructor, creates an GlobRef object referencing an element in - * global memory. - */ - GlobRef() - : _gptr(DART_GPTR_NULL) { - } +/** +* Reference semantics forbid declaration without definition. +*/ +GlobRef() = delete; - /** - * Constructor, creates an GlobRef object referencing an element in global - * memory. - */ - template - explicit GlobRef( - /// Pointer to referenced object in global memory - GlobPtr & gptr) - : GlobRef(gptr.dart_gptr()) - { } +/** +* Constructor, creates an GlobRef object referencing an element in global +* memory. +*/ +template +explicit GlobRef( +/// Pointer to referenced object in global memory +GlobPtr & gptr) +: GlobRef(gptr.dart_gptr()) +{ } - /** - * Constructor, creates an GlobRef object referencing an element in global - * memory. - */ - 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. +*/ +template +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( +/// 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. +*/ +explicit GlobRef(dart_gptr_t dart_gptr) +: _gptr(dart_gptr) +{ +DASH_LOG_TRACE_VAR("GlobRef(dart_gptr_t)", dart_gptr); +} + +/** +* 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(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; + +operator T() const { +return load(); +} /** - * Constructor, creates an GlobRef object referencing an element in global - * memory. + * Implicit conversion to const type. */ - explicit GlobRef(dart_gptr_t dart_gptr) - : _gptr(dart_gptr) - { - DASH_LOG_TRACE_VAR("GlobRef(dart_gptr_t)", dart_gptr); + operator const_type() const { + return const_type(_gptr); } /** - * Copy constructor. + * Explicit conversion to non-const type. */ - GlobRef( - /// GlobRef instance to copy. - const GlobRef & other) - : _gptr(other._gptr) - { } - - self_t & operator=(const self_t & other) = delete; - - operator T() const { - return load(); + explicit + operator nonconst_type() const { + return nonconst_type(_gptr); } + dart_gptr_t dart_gptr() const { return _gptr; } @@ -115,13 +141,22 @@ 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 - GlobRef operator=(const T & value) const { + /** + * 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) const { store(value); - return *this; + return value; } /** @@ -129,6 +164,8 @@ class GlobRef> */ 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( @@ -146,7 +183,7 @@ class GlobRef> * Set the value of the shared atomic variable. */ inline void store(const T & value) const { - exchange(value); + set(value); } /// atomically fetches value @@ -154,8 +191,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), @@ -169,7 +206,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(); @@ -180,13 +217,16 @@ 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, + "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, @@ -211,10 +251,12 @@ class GlobRef> /// Value to be added to global atomic variable. 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()); - value_type res; + nonconst_value_type res; dart_ret_t ret = dart_fetch_and_op( _gptr, reinterpret_cast(&value), @@ -243,12 +285,14 @@ class GlobRef> * \see \c dash::atomic::compare_exchange */ 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); 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), @@ -268,6 +312,8 @@ class GlobRef> */ void add(const T & value) const { + static_assert(std::is_same::value, + "Cannot modify value referenced by GlobRef!"); op(dash::plus(), value); } @@ -277,7 +323,7 @@ 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 { @@ -306,32 +352,104 @@ class GlobRef> return fetch_op(dash::plus(), -value); } - /// prefix atomically increment value by one + /** + * DASH specific variant which is faster than \c fetch_multiply + * but does not return value + */ + void multiply(const T & value) const + { + 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) const + { + return fetch_op(dash::multiply(), value); + } + + /** + * prefix atomically increment value by one + * + * \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. + */ T operator++ () const { return fetch_add(1) + 1; } - /// postfix atomically increment value by one + /** + * postfix atomically increment value by one + * + * \return The value of the referenced shared variable before the + * operation. + */ T operator++ (int) const { return fetch_add(1); } - /// prefix atomically decrement value by one + /** + * prefix atomically decrement value by one + * + * \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. + */ T operator-- () const { return fetch_sub(1) - 1; } - /// postfix atomically decrement value by one + /** + * postfix atomically decrement value by one + * + * \return The value of the referenced shared variable before the + * operation. + */ T operator-- (int) const { return fetch_sub(1); } - /// atomically increment value by ref + /** + * atomically increment value by ref + * + * \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. + */ T operator+=(const T & value) const { return fetch_add(value) + value; } - /// atomically decrement value by ref + /** + * 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 + * http://en.cppreference.com/w/cpp/atomic/atomic/operator_arith2. + */ 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 43827c664..1f083feb1 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(const 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(const 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, + const dash::GlobRef>& ref, const T & expected, const T & desired) { @@ -78,7 +78,7 @@ template< typename T, typename BinaryOp > void op( - const 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( - const 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( - const dash::GlobRef> & ref, + const dash::GlobRef>& ref, const T & value) { ref.add(value); @@ -126,12 +126,27 @@ typename std::enable_if< std::is_integral::value, void>::type sub( - const dash::GlobRef> & ref, + const dash::GlobRef>& ref, const T & value) { ref.sub(value); } +/** + * Atomic multiply operation on the referenced shared value. + */ +template +typename std::enable_if< + std::is_integral::value, + void>::type +multiply( + const dash::GlobRef>& ref, + const T & value) +{ + ref.multiply(value); +} + + /** * Atomic fetch-and-add operation on the referenced shared value. * @@ -143,7 +158,7 @@ typename std::enable_if< std::is_integral::value, T>::type fetch_add( - const dash::GlobRef> & ref, + const dash::GlobRef>& ref, /// Value to be added to global atomic variable. const T & value) { @@ -161,13 +176,13 @@ typename std::enable_if< std::is_integral::value, T>::type fetch_sub( - const dash::GlobRef> & ref, + const dash::GlobRef>& ref, /// Value to be subtracted from global atomic variable. const T & value) { return ref.fetch_sub(value); } - + } // namespace atomic } // namespace dash diff --git a/dash/include/dash/matrix/internal/Matrix-inl.h b/dash/include/dash/matrix/internal/Matrix-inl.h index f394a07cc..cc97fd767 100644 --- a/dash/include/dash/matrix/internal/Matrix-inl.h +++ b/dash/include/dash/matrix/internal/Matrix-inl.h @@ -476,7 +476,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); @@ -495,7 +495,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 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 f6f3dbbb9..1acf8e650 100644 --- a/dash/test/types/AtomicTest.cc +++ b/dash/test/types/AtomicTest.cc @@ -329,11 +329,33 @@ TEST_F(AtomicTest, AlgorithmVariant){ } dash::barrier(); - 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*(std::pow(-1, dash::size())))) + ); + } } TEST_F(AtomicTest, AtomicInContainer){ @@ -376,8 +398,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(); @@ -389,8 +412,6 @@ TEST_F(AtomicTest, AtomicInterface){ dash::barrier(); ASSERT_EQ_U(array[0].load(), dash::size()); - ASSERT_EQ_U(array[1].load(), dash::size()); - ASSERT_EQ_U(array[2].load(), -dash::size()); ASSERT_EQ_U(array[3].load(), -dash::size()); dash::barrier(); @@ -415,9 +436,13 @@ 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(); + 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); @@ -426,6 +451,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){ @@ -506,16 +535,141 @@ TEST_F(AtomicTest, AtomicSignal){ } } + TEST_F(AtomicTest, ElementCompare){ using value_t = int; using atom_t = dash::Atomic; using array_t = dash::Array; + array_t array(dash::size()); + if (dash::size() < 2) { SKIP_TEST_MSG("At least 2 units required"); } + // 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(); + 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(); + +} + +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()); +} + +TEST_F(AtomicTest, AsyncAtomic){ + using value_t = int; + using atom_t = dash::Atomic; + using array_t = dash::Array; + array_t array(dash::size()); + dash::fill(array.begin(), array.end(), 0); dash::barrier(); @@ -529,3 +683,4 @@ TEST_F(AtomicTest, ElementCompare){ // OK ASSERT_EQ_U(array[0].get(), array[dash::myid()]); } +