DASH  0.3.0
Shared.h
1 #ifndef DASH__SHARED_H_
2 #define DASH__SHARED_H_
3 
4 #include <memory>
5 
7 
8 #include <dash/GlobRef.h>
9 #include <dash/memory/MemorySpace.h>
10 #include <dash/memory/UniquePtr.h>
11 #include <dash/allocator/GlobalAllocator.h>
12 
13 #include <dash/iterator/GlobIter.h>
14 
15 namespace dash {
16 
22 template <typename ElementType>
23 class Shared {
24 private:
26  typedef ElementType element_t;
27 
28 public:
29  typedef size_t size_type;
30  typedef size_t difference_type;
31 
34 
35  // Note: For dash::Shared<dash::Atomic<T>>, reference type is
36  // dash::GlobRef<dash::Atomic<T>> with value_type T.
37  //
38  // See definition of dash::GlobRef in dash/atomic/GlobAtomicRef.h.
39  typedef typename reference::value_type value_type;
40 
41 private:
44  using unique_gptr_t = decltype(
45  dash::allocate_unique<element_t>(allocator_type{}, std::size_t{}));
46  using pointer_t = typename unique_gptr_t::pointer;
47 
48  template <typename T_>
49  friend void swap(Shared<T_>& a, Shared<T_>& b);
50 
51  static constexpr size_t nels = 1;
52  static constexpr size_t nbytes = sizeof(element_t);
53 
54 private:
55  dash::Team* m_team{nullptr};
57  memory_type m_memory_resource{nullptr};
58  allocator_type m_allocator{};
59  unique_gptr_t m_data{};
60  pointer_t m_glob_pointer;
61 
62 public:
71  : Shared(value_type{}, owner, team)
72  {
73  DASH_LOG_TRACE(
74  "Shared.Shared(team,owner) >", "finished delegating constructor");
75  }
76 
83  const value_type& val,
88  : m_team(&team)
89  , m_owner(owner)
90  , m_memory_resource(nbytes, team)
91  , m_allocator(&m_memory_resource)
92  {
93  DASH_LOG_DEBUG_VAR("Shared.Shared(value,team,owner)()", owner);
94  if (dash::is_initialized()) {
95  DASH_ASSERT_RETURNS(init(val), true);
96  }
97  }
98 
102  ~Shared() = default;
103 
107  Shared(const self_t& other) = delete;
108 
112  Shared(self_t&& other) noexcept
113  : m_team(other.m_team)
114  , m_owner(other.m_owner)
115  , m_memory_resource(std::move(other.m_memory_resource))
116  , m_allocator(&m_memory_resource)
117  {
118  auto gptr = other.m_data.release();
119  m_data = unique_gptr_t{
120  gptr, typename unique_gptr_t::deleter{m_allocator, nels}};
121  DASH_LOG_DEBUG("Shared.Shared(Shared&&) >");
122  }
123 
127  self_t& operator=(const self_t& other) = delete;
128 
132  self_t& operator=(self_t&& other) DASH_NOEXCEPT
133  {
134  if (this == &other) {
135  return *this;
136  }
137 
138  m_team = other.m_team;
139  m_owner = other.m_owner;
140  // a) release old resources with current memory resource
141  m_data.reset();
142 
143  // b) move the memory resource
144  m_memory_resource = std::move(other.m_memory_resource);
145  // do no move the allocator because we already have one...
146  DASH_ASSERT_EQ(
147  m_allocator.resource(),
148  &m_memory_resource,
149  "invalid state in move assignment");
150 
151  // c) move the data, set pointer
152  m_data.reset(other.m_data.release());
153 
154  m_glob_pointer = other.m_glob_pointer;
155 
156  if (m_team->myid() == m_owner) {
157  DASH_ASSERT_EQ(
158  m_glob_pointer, m_data.get(), "invalid state in move assignment");
159  }
160 
161  DASH_LOG_DEBUG("Shared.Shared(Shared&&) >");
162  return *this;
163  }
164 
175  bool init(value_type val = value_type{})
176  {
177  if (!dash::is_initialized()) {
178  DASH_THROW(
179  dash::exception::RuntimeError, "runtime not properly initialized");
180  }
181 
182  // If our Shared has already a non-null pointer let us return it. The user
183  // has first to deallocate it.
184  if (m_glob_pointer) {
185  DASH_LOG_ERROR("dash::Shared::init", "Shared scalar is already initialized");
186  return false;
187  }
188 
189  // Shared value is only allocated at unit 0:
190  if (!m_data && m_team->myid() == m_owner) {
191  DASH_LOG_DEBUG(
192  "Shared.init(value,team,owner)",
193  "allocating shared value in local memory");
194 
195  m_data = std::move(dash::allocate_unique<element_t>(m_allocator, nels));
196 
197  DASH_ASSERT_MSG(m_data, "null pointer after allocation");
198 
199  auto* laddr = static_cast<element_t*>(m_data.get().local());
200 
201  // get the underlying allocator for local memory space
202  auto local_alloc = m_memory_resource.get_allocator();
203  using allocator_traits = std::allocator_traits<decltype(local_alloc)>;
204 
205  // copy construct based on val
206  allocator_traits::construct(local_alloc, laddr, element_t{val});
207  m_glob_pointer = m_data.get();
208  }
209  // Broadcast global pointer of shared value at unit 0 to all units:
211 
212  DASH_ASSERT_RETURNS(
213  dart_bcast(
214  &m_glob_pointer, ds.nelem, ds.dtype, m_owner, m_team->dart_id()),
215  DART_OK);
216 
217  DASH_LOG_DEBUG_VAR("Shared.init(value,team,owner) >", m_glob_pointer);
218  DASH_LOG_DEBUG("Shared.init(value,team,owner) >");
219 
220  return static_cast<bool>(m_glob_pointer);
221  }
222 
226  void set(const value_type& val)
227  {
228  DASH_LOG_DEBUG("Shared.set()");
229  DASH_LOG_DEBUG_VAR("Shared.set", m_owner);
230  DASH_LOG_DEBUG_VAR("Shared.set", m_glob_pointer);
231  DASH_ASSERT(m_glob_pointer);
232  this->get().set(val);
233  DASH_LOG_DEBUG("Shared.set >");
234  }
235 
239  reference get()
240  {
241  DASH_LOG_DEBUG("Shared.cget()");
242  DASH_LOG_DEBUG_VAR("Shared.cget", m_owner);
243  DASH_LOG_DEBUG_VAR("Shared.get", m_glob_pointer);
244  DASH_ASSERT(static_cast<bool>(m_glob_pointer));
245  return reference(m_glob_pointer.dart_gptr());
246  }
247 
251  const_reference get() const
252  {
253  DASH_LOG_DEBUG("Shared.get()");
254  DASH_LOG_DEBUG_VAR("Shared.get", m_owner);
255  DASH_LOG_DEBUG_VAR("Shared.get", m_glob_pointer);
256  DASH_ASSERT(m_glob_pointer);
257  return const_reference(m_glob_pointer.dart_gptr());
258  }
259 
264  constexpr value_type const* local() const noexcept
265  {
266  return (m_team->myid() == m_owner) ? m_glob_pointer.local() : nullptr;
267  }
268 
273  value_type* local() noexcept
274  {
275  return (m_team->myid() == m_owner) ? m_glob_pointer.local() : nullptr;
276  }
277 
281  dash::team_unit_t owner() const noexcept
282  {
283  return m_owner;
284  }
285 
289  dash::Team& team() const noexcept
290  {
291  return *m_team;
292  }
293 
297  void flush()
298  {
299  DASH_ASSERT(static_cast<bool>(m_glob_pointer));
300  DASH_ASSERT_RETURNS(
301  dart_flush(static_cast<dart_gptr_t>(m_glob_pointer)), DART_OK);
302  }
303 
308  void barrier()
309  {
310  flush();
311  DASH_ASSERT(m_team != nullptr);
312  m_team->barrier();
313  }
314 
318  inline dart_gptr_t dart_gptr() const noexcept
319  {
320  return m_glob_pointer;
321  }
322 };
323 
324 template <typename T>
325 void swap(dash::Shared<T>& a, dash::Shared<T>& b)
326 {
327  using std::swap;
328 
329  swap(a.m_team, b.m_team);
330  swap(a.m_owner, b.m_owner);
331  swap(a.m_memory_resource, b.m_memory_resource);
332 
333  // we cannot simply swap two unique_ptr as this swaps also the deleters.
334  // That is not what we want, because we swapped already the underlying
335  // resources
336 
337  auto ptrA = a.m_data.release();
338  a.m_data.reset(b.m_data.release());
339  b.m_data.reset(ptrA);
340 
341  swap(a.m_glob_pointer, b.m_glob_pointer);
342 }
343 
344 } // namespace dash
345 
346 #endif // DASH__SHARED_H_
dash::Team & team() const noexcept
The dash::Team that created this shared object.
Definition: Shared.h:289
This class is a simple memory pool which holds allocates elements of size ValueType.
Definition: AllOf.h:8
Signals success.
Definition: dart_types.h:33
void barrier()
Flush global memory of shared value and synchronize its associated units.
Definition: Shared.h:308
dart_ret_t dart_bcast(void *buf, size_t nelem, dart_datatype_t dtype, dart_team_unit_t root, dart_team_t team)
DART Equivalent to MPI broadcast.
self_t & operator=(self_t &&other) DASH_NOEXCEPT
Move-assignment operator.
Definition: Shared.h:132
Shared(team_unit_t owner=team_unit_t(0), Team &team=dash::Team::All())
Constructor, allocates shared value at single unit in specified team.
Definition: Shared.h:66
bool is_initialized()
Check whether DASH has been initialized already.
A Team instance specifies a subset of all available units.
Definition: Team.h:41
~Shared()=default
Destructor, frees shared memory.
Shared(self_t &&other) noexcept
Move-constructor.
Definition: Shared.h:112
self_t & operator=(const self_t &other)=delete
Assignment operator: DELETED.
value_type * local() noexcept
Native pointer to the starting address of the local memory of the unit that initialized this dash::Sh...
Definition: Shared.h:273
DART Global pointer type.
Definition: dart_globmem.h:77
dash::team_unit_t owner() const noexcept
The unit owning the memory in the global address space.
Definition: Shared.h:281
struct dash::unit_id< dash::local_unit, dart_team_unit_t > team_unit_t
Unit ID to use for team-local IDs.
Definition: Types.h:319
Shared(const value_type &val, team_unit_t owner=team_unit_t(0), Team &team=dash::Team::All())
Constructor, allocates shared value at single unit in specified team.
Definition: Shared.h:81
void flush()
Flush global memory of shared value.
Definition: Shared.h:297
dart_gptr_t dart_gptr() const noexcept
Get underlying DART global pointer of the shared variable.
Definition: Shared.h:318
#define DART_UNDEFINED_UNIT_ID
Undefined unit ID.
Definition: dart_types.h:160
Shared access to a value in global memory across a team.
Definition: Shared.h:23
constexpr value_type const * local() const noexcept
Native pointer to the starting address of the local memory of the unit that initialized this dash::Sh...
Definition: Shared.h:264
Convencience wrapper to determine the DART type and number of elements required for the given templat...
Definition: Types.h:295
static Team & All()
The invariant Team instance containing all available units.
Definition: Team.h:213
bool init(value_type val=value_type{})
Collective allocation of a shared variable with an initial value.
Definition: Shared.h:175
dart_team_t dart_id() const
Index of this team relative to global team dash::Team::All().
Definition: Team.h:522
dart_ret_t dart_flush(dart_gptr_t gptr)
Guarantee completion of all outstanding operations involving a segment on a certain unit...