DASH  0.3.0
EpochSynchronizedAllocator.h
1 #ifndef DASH__ALLOCATOR__EPOCH_SYNCHRONIZED_ALLOCATOR_H__INCLUDED
2 #define DASH__ALLOCATOR__EPOCH_SYNCHRONIZED_ALLOCATOR_H__INCLUDED
3 
4 #include <dash/dart/if/dart.h>
5 
6 #include <dash/Team.h>
7 #include <dash/Types.h>
8 
9 #include <dash/internal/Logging.h>
10 
11 #include <dash/GlobPtr.h>
12 #include <dash/allocator/AllocatorTraits.h>
13 #include <dash/allocator/AllocatorBase.h>
14 #include <dash/allocator/internal/Types.h>
15 #include <dash/memory/MemorySpace.h>
16 
17 #include <algorithm>
18 #include <utility>
19 #include <vector>
20 
21 namespace dash {
22 
35 template <
37  typename ElementType,
39  typename LMemSpace = dash::HostSpace,
41  global_allocation_policy AllocationPolicy =
44  template <class T> class LocalAlloc = allocator::DefaultAllocator>
46  template <class T, class U>
47  friend bool operator==(
49  T,
50  LMemSpace,
51  AllocationPolicy,
52  LocalAlloc> &lhs,
54  U,
55  LMemSpace,
56  AllocationPolicy,
57  LocalAlloc> &rhs);
58  template <class T, class U>
59  friend bool operator!=(
61  T,
62  LMemSpace,
63  AllocationPolicy,
64  LocalAlloc> &lhs,
66  U,
67  LMemSpace,
68  AllocationPolicy,
69  LocalAlloc> &rhs);
70 
72  using memory_traits = typename dash::memory_space_traits<LMemSpace>;
73 
74  static_assert(memory_traits::is_local::value, "memory space must be local");
75 
76  static_assert(
78  "currently, only the epoch_synchronized allocation policy is "
79  "supported");
80 
82  ElementType,
83  LMemSpace,
84  AllocationPolicy,
85  LocalAlloc>;
86 
87  static constexpr size_t const alignment = alignof(ElementType);
88 
89  using allocator_traits = std::allocator_traits<LocalAlloc<ElementType>>;
90 
92 
93  // tuple to hold the local pointer
94  using allocation_rec_t =
95  allocator::allocation_rec<typename allocator_traits::pointer>;
96 
97 public:
98  using local_allocator_type = LocalAlloc<ElementType>;
100  using value_type = ElementType;
101  using size_type = dash::default_size_t;
102  using difference_type = dash::default_index_t;
103 
104  using pointer = dart_gptr_t;
105  using const_pointer = dart_gptr_t const;
106  using void_pointer = dart_gptr_t;
107  using const_void_pointer = dart_gptr_t const;
108 
109  using local_pointer = typename allocator_traits::pointer;
110  using const_local_pointer = typename allocator_traits::const_pointer;
111  using local_void_pointer = typename allocator_traits::void_pointer;
112  using const_local_void_pointer =
113  typename allocator_traits::const_void_pointer;
114 
115  using allocation_policy =
116  std::integral_constant<global_allocation_policy, AllocationPolicy>;
117 
119  template <class U>
120  using rebind = dash::
121  EpochSynchronizedAllocator<U, LMemSpace, AllocationPolicy, LocalAlloc>;
122 
123 public:
130  Team const &team, LMemSpace *r = nullptr) noexcept;
131 
137  EpochSynchronizedAllocator(const self_t &other) noexcept;
138 
144  self_t &operator=(const self_t &other) noexcept;
145 
150  EpochSynchronizedAllocator(self_t &&other) noexcept;
151 
155  self_t &operator=(self_t &&other) noexcept;
156 
160  void swap(self_t &other) noexcept;
161 
166  ~EpochSynchronizedAllocator() noexcept;
167 
171  size_type max_size() const noexcept
172  {
173  return size_type(-1) / sizeof(ElementType);
174  }
184  pointer attach(local_pointer lptr, size_type num_local_elem);
185 
194  void detach(pointer gptr, size_type num_local_elem);
195 
204  local_pointer allocate_local(size_type num_local_elem);
205 
213  void deallocate_local(local_pointer lptr, size_type num_local_elem);
214 
223  pointer allocate(size_type num_local_elem);
224 
234  void deallocate(pointer gptr, size_type num_local_elem);
235 
239  inline local_allocator_type get_local_allocator() const noexcept
240  {
241  return _alloc;
242  }
243 
244 private:
245  struct BinaryCmpLocalPointer {
246  bool operator()(const allocation_rec_t &a, const allocation_rec_t &b)
247  {
248  return reinterpret_cast<const uintptr_t>(a.lptr()) <
249  reinterpret_cast<const uintptr_t>(b.lptr());
250  }
251  };
252 
253 private:
258  void clear() DASH_ASSERT_NOEXCEPT
259  {
260  DASH_LOG_DEBUG("EpochSynchronizedAllocator.clear()");
261 
262  for (auto const &segment : _segments) {
263  deallocate(segment.gptr(), segment.length());
264  }
265  _segments.clear();
266  DASH_LOG_DEBUG("EpochSynchronizedAllocator.clear >");
267  }
268 
269  template <class ForwardIt, class Compare>
270  ForwardIt binary_find(
271  ForwardIt first,
272  ForwardIt last,
273  const allocation_rec_t &value,
274  Compare comp)
275  {
276  first = std::lower_bound(first, last, value, comp);
277  return first != last && !comp(value, *first) ? first : last;
278  }
279 
280  typename std::vector<allocation_rec_t>::iterator do_local_allocate(
281  size_type num_local_elem)
282  {
283  auto lp = allocator_traits::allocate(_alloc, num_local_elem);
284 
285  if (!lp && num_local_elem > 0) {
286  DASH_LOG_ERROR(
287  "EpochSynchronizedAllocator.allocate_local",
288  "cannot allocate local memory segment",
289  num_local_elem);
290  throw std::bad_alloc{};
291  }
292 
293  allocation_rec_t rec{lp, num_local_elem, DART_GPTR_NULL};
294 
295  auto pos = std::lower_bound(
296  std::begin(_segments),
297  std::end(_segments),
298  rec,
299  BinaryCmpLocalPointer{});
300 
301  return _segments.emplace(pos, std::move(rec));
302  }
303 
304  typename std::vector<allocation_rec_t>::iterator lookup_segment_by_lptr(
305  local_pointer lptr)
306  {
307  allocation_rec_t rec{lptr, 0, DART_GPTR_NULL};
308 
309  return binary_find(
310  std::begin(_segments),
311  std::end(_segments),
312  rec,
313  BinaryCmpLocalPointer{});
314  }
315 
316  typename std::vector<allocation_rec_t>::iterator lookup_segment_by_gptr(
317  pointer gptr)
318  {
319  return std::find_if(
320  std::begin(_segments),
321  std::end(_segments),
322  [gptr](const allocation_rec_t &a) {
323  return DART_GPTR_EQUAL(a.gptr(), gptr);
324  });
325  }
326 
327 private:
328  dash::Team const * _team{};
329  std::vector<allocation_rec_t> _segments;
330  local_allocator_type _alloc;
331  policy_type _policy;
332 
333 }; // class EpochSynchronizedAllocator
334 
336 
337 template <
338  typename ElementType,
339  typename LMemSpace,
340  global_allocation_policy AllocationPolicy,
341  template <class> class LocalAlloc>
343  ElementType,
344  LMemSpace,
345  AllocationPolicy,
346  LocalAlloc>::
347  EpochSynchronizedAllocator(Team const &team, LMemSpace *r) noexcept
348  : _team(&team)
349  , _alloc(
350  r ? r
351  : static_cast<LMemSpace *>(
354  typename memory_traits::memory_space_type_category>()))
355  , _policy{}
356 {
357  DASH_LOG_DEBUG(
358  "EpochSynchronizedAllocator.SymmetricAllocator(team, alloc) >");
359  _segments.reserve(1);
360 }
361 
362 template <
363  typename ElementType,
364  typename LMemSpace,
365  global_allocation_policy AllocationPolicy,
366  template <class> class LocalAlloc>
368  ElementType,
369  LMemSpace,
370  AllocationPolicy,
371  LocalAlloc>::EpochSynchronizedAllocator(self_t const &other) noexcept
372 {
373  operator=(other);
374 }
375 
376 template <
377  typename ElementType,
378  typename LMemSpace,
379  global_allocation_policy AllocationPolicy,
380  template <class> class LocalAlloc>
382  ElementType,
383  LMemSpace,
384  AllocationPolicy,
385  LocalAlloc>::EpochSynchronizedAllocator(self_t &&other) noexcept
386  : _team(other._team)
387  , _alloc(std::move(other._alloc))
388  , _segments(std::move(other._segments))
389  , _policy(other._policy)
390 {
391  other.clear();
392 }
393 
394 template <
395  typename ElementType,
396  typename LMemSpace,
397  global_allocation_policy AllocationPolicy,
398  template <class> class LocalAlloc>
400  ElementType,
401  LMemSpace,
402  AllocationPolicy,
403  LocalAlloc>::self_t &
405  ElementType,
406  LMemSpace,
407  AllocationPolicy,
408  LocalAlloc>::operator=(self_t const &other) noexcept
409 {
410  if (&other == this) {
411  return *this;
412  }
413 
414  _alloc = other._alloc;
415 
416  _team = other._team;
417 
418  _policy = other._policy;
419 
420  return *this;
421 }
422 
423 template <
424  typename ElementType,
425  typename LMemSpace,
426  global_allocation_policy AllocationPolicy,
427  template <class> class LocalAlloc>
429  ElementType,
430  LMemSpace,
431  AllocationPolicy,
432  LocalAlloc>::self_t &
434  ElementType,
435  LMemSpace,
436  AllocationPolicy,
437  LocalAlloc>::operator=(self_t &&other) noexcept
438 {
439  if (&other == this) {
440  return *this;
441  }
442 
443  if (_alloc == other._alloc) {
444  // If the local allocators equal each other we can move everything
445  clear();
446  swap(other);
447  }
448  else {
449  // otherwise we do not touch any data and copy assign it
450  operator=(other);
451  }
452 
453  return *this;
454 }
455 
456 template <
457  typename ElementType,
458  typename LMemSpace,
459  global_allocation_policy AllocationPolicy,
460  template <class> class LocalAlloc>
462  ElementType,
463  LMemSpace,
464  AllocationPolicy,
465  LocalAlloc>::~EpochSynchronizedAllocator() noexcept
466 {
467  clear();
468 }
469 
470 template <
471  typename ElementType,
472  typename LMemSpace,
473  global_allocation_policy AllocationPolicy,
474  template <class> class LocalAlloc>
476  ElementType,
477  LMemSpace,
478  AllocationPolicy,
479  LocalAlloc>::swap(self_t &other) noexcept
480 {
481  std::swap(_team, other._team);
482  std::swap(_alloc, other._alloc);
483  std::swap(_segments, other._segments);
484  std::swap(_policy, other._policy);
485 }
486 
487 template <
488  typename ElementType,
489  typename LMemSpace,
490  global_allocation_policy AllocationPolicy,
491  template <class> class LocalAlloc>
493  ElementType,
494  LMemSpace,
495  AllocationPolicy,
496  LocalAlloc>::local_pointer
498  ElementType,
499  LMemSpace,
500  AllocationPolicy,
501  LocalAlloc>::allocate_local(size_type num_local_elem)
502 {
503  DASH_LOG_DEBUG(
504  "SymmetricAllocator.allocate_local(n)",
505  "number of local values:",
506  num_local_elem);
507 
508  auto it = do_local_allocate(num_local_elem);
509 
510  DASH_ASSERT_MSG(it->lptr() != nullptr, "invalid pointer");
511 
512  return it->lptr();
513 }
514 
515 template <
516  typename ElementType,
517  typename LMemSpace,
518  global_allocation_policy AllocationPolicy,
519  template <class> class LocalAlloc>
521  ElementType,
522  LMemSpace,
523  AllocationPolicy,
524  LocalAlloc>::
525  deallocate_local(local_pointer lptr, size_type num_local_elem)
526 {
527  DASH_LOG_DEBUG(
528  "EpochSynchronizedAllocator.deallocate_local(n)",
529  "local pointer",
530  lptr,
531  "length:",
532  num_local_elem);
533 
534  auto pos = lookup_segment_by_lptr(lptr);
535 
536  if (pos == std::end(_segments)) {
537  DASH_LOG_ERROR(
538  "EpochSynchronizedAllocator.deallocate_local",
539  "invalid local pointer",
540  lptr);
541  return;
542  }
543 
544  DASH_ASSERT_EQ(pos->length(), num_local_elem, "Invalid block length");
545 
546  if (!DART_GPTR_ISNULL(pos->gptr())) {
547  DASH_LOG_ERROR(
548  "EpochSynchronizedAllocator.deallocate_local",
549  "local pointer must not be attached to global memory",
550  lptr);
551  return;
552  }
553 
554  allocator_traits::deallocate(_alloc, pos->lptr(), pos->length());
555 
556  _segments.erase(pos);
557 }
558 
559 template <
560  typename ElementType,
561  typename LMemSpace,
562  global_allocation_policy AllocationPolicy,
563  template <class> class LocalAlloc>
565  ElementType,
566  LMemSpace,
567  AllocationPolicy,
568  LocalAlloc>::pointer
570  ElementType,
571  LMemSpace,
572  AllocationPolicy,
573  LocalAlloc>::attach(local_pointer const lptr, size_type num_local_elem)
574 {
575  DASH_LOG_DEBUG(
576  "EpochSynchronizedAllocator.attach",
577  "local_pointer:",
578  lptr,
579  "length:",
580  num_local_elem);
581 
582  auto pos = lookup_segment_by_lptr(lptr);
583 
584  if (pos == std::end(_segments)) {
585  DASH_LOG_ERROR(
586  "EpochSynchronizedAllocator.attach", "Invalid local pointer", lptr);
587  return DART_GPTR_NULL;
588  }
589 
590  DASH_ASSERT_EQ(num_local_elem, pos->length(), "invalid block length");
591 
592  auto gptr = _policy.do_global_attach(
593  _team->dart_id(), pos->lptr(), pos->length() * sizeof(ElementType));
594 
595  DASH_ASSERT_MSG(!DART_GPTR_ISNULL(gptr), "gptr must not be null");
596 
597  pos->gptr() = gptr;
598 
599  return gptr;
600 }
601 
602 template <
603  typename ElementType,
604  typename LMemSpace,
605  global_allocation_policy AllocationPolicy,
606  template <class> class LocalAlloc>
608  ElementType,
609  LMemSpace,
610  AllocationPolicy,
611  LocalAlloc>::detach(pointer const gptr, size_type num_local_elem)
612 {
613  DASH_LOG_DEBUG(
614  "EpochSynchronizedAllocator.detach",
615  "global pointer:",
616  gptr,
617  "length:",
618  num_local_elem);
619 
620  if (DART_GPTR_ISNULL(gptr)) {
621  return;
622  }
623 
624  auto pos = lookup_segment_by_gptr(gptr);
625 
626  if (pos == std::end(_segments)) {
627  DASH_LOG_ERROR(
628  "EpochSynchronizedAllocator.detach", "Invalid global pointer", gptr);
629  return;
630  }
631 
632  DASH_ASSERT_EQ(num_local_elem, pos->length(), "invalid block length");
633 
634  _policy.do_global_detach(pos->gptr());
635 
636  pos->gptr() = DART_GPTR_NULL;
637 }
638 
639 template <
640  typename ElementType,
641  typename LMemSpace,
642  global_allocation_policy AllocationPolicy,
643  template <class> class LocalAlloc>
645  ElementType,
646  LMemSpace,
647  AllocationPolicy,
648  LocalAlloc>::deallocate(pointer gptr, size_type num_local_elem)
649 {
650  DASH_LOG_DEBUG(
651  "EpochSynchronizedAllocator.deallocate", "deallocate local memory");
652 
653  if (DART_GPTR_ISNULL(gptr)) {
654  return;
655  }
656 
657  auto pos = std::find_if(
658  std::begin(_segments),
659  std::end(_segments),
660  [gptr](const allocation_rec_t &a) {
661  return DART_GPTR_EQUAL(a.gptr(), gptr);
662  });
663 
664  if (pos == std::end(_segments)) {
665  DASH_LOG_ERROR(
666  "EpochSynchronizedAllocator.detach", "Invalid global pointer", gptr);
667  return;
668  }
669 
670  DASH_ASSERT_EQ(pos->length(), num_local_elem, "invalid block length");
671 
672  _policy.do_global_detach(pos->gptr());
673 
674  allocator_traits::deallocate(_alloc, pos->lptr(), pos->length());
675 
676  _segments.erase(pos);
677 }
678 
679 template <
680  typename ElementType,
681  typename LMemSpace,
682  global_allocation_policy AllocationPolicy,
683  template <class> class LocalAlloc>
685  ElementType,
686  LMemSpace,
687  AllocationPolicy,
688  LocalAlloc>::pointer
690  ElementType,
691  LMemSpace,
692  AllocationPolicy,
693  LocalAlloc>::allocate(size_type num_local_elem)
694 {
695  DASH_LOG_DEBUG(
696  "EpochSynchronizedAllocator.allocate",
697  "num_local_elem",
698  num_local_elem);
699 
700  auto it = do_local_allocate(num_local_elem);
701 
702  DASH_ASSERT_MSG(it->lptr() != nullptr, "local pointer must not be NULL");
703 
704  auto gptr = _policy.do_global_attach(
705  _team->dart_id(), it->lptr(), num_local_elem * sizeof(ElementType));
706 
707  DASH_ASSERT_MSG(!DART_GPTR_ISNULL(gptr), "gptr must not be null");
708 
709  it->gptr() = gptr;
710 
711  return gptr;
712 }
713 
714 template <
715  class T,
716  class U,
717  class LocalMemSpace,
718  global_allocation_policy AllocationPolicy,
719  template <class> class LocalAlloc>
720 bool operator==(
722  T,
723  LocalMemSpace,
724  AllocationPolicy,
725  LocalAlloc> &lhs,
727  U,
728  LocalMemSpace,
729  AllocationPolicy,
730  LocalAlloc> &rhs)
731 {
732  return (
733  sizeof(T) == sizeof(U) && *(lhs._team) == *(rhs._team) &&
734  lhs._alloc == rhs._alloc);
735 }
736 
737 template <
738  class T,
739  class U,
740  class LocalMemSpace,
741  global_allocation_policy AllocationPolicy,
742  template <class> class LocalAlloc>
743 bool operator!=(
745  T,
746  LocalMemSpace,
747  AllocationPolicy,
748  LocalAlloc> &lhs,
750  U,
751  LocalMemSpace,
752  AllocationPolicy,
753  LocalAlloc> &rhs)
754 {
755  return !(lhs == rhs);
756 }
757 
758 } // namespace dash
759 
760 #endif // DASH__ALLOCATOR__EPOCH_SYNCHRONIZED_ALLOCATOR_H__INCLUDED
MemorySpace< MSpaceDomainCategory, MSpaceTypeCategory > * get_default_memory_space()
Forward declarations.
Definition: MemorySpace.h:29
internal::default_unsigned_index default_size_t
Unsigned integer type used as default for size values.
Definition: Types.h:69
constexpr auto end(RangeType &&range) -> decltype(std::forward< RangeType >(range).end())
Definition: Range.h:98
void swap(self_t &other) noexcept
Swap two collective Allocators.
This class is a simple memory pool which holds allocates elements of size ValueType.
Definition: AllOf.h:8
constexpr auto begin(RangeType &&range) -> decltype(std::forward< RangeType >(range).begin())
Definition: Range.h:89
~EpochSynchronizedAllocator() noexcept
Destructor.
Encapsulates a memory allocation and deallocation strategy of global memory regions distributed acros...
local_allocator_type get_local_allocator() const noexcept
Returns a copy of the local allocator object associated with the vector.
GlobIter find_if(GlobIter first, GlobIter last, UnaryPredicate predicate)
Returns an iterator to the first element in the range [first,last) that satisfies the predicate p...
Definition: Find.h:104
Returns second operand.
Definition: Operation.h:201
size_type max_size() const noexcept
Estimate the largest supported size.
pointer attach(local_pointer lptr, size_type num_local_elem)
Register pre-allocated local memory segment of num_local_elem elements in global memory space...
global_allocation_policy
ElementType value_type
Allocator Traits.
internal::default_signed_index default_index_t
Signed integer type used as default for index values.
Definition: Types.h:59
#define DART_GPTR_NULL
A NULL global pointer.
Definition: dart_globmem.h:105
A Team instance specifies a subset of all available units.
Definition: Team.h:41
self_t & operator=(const self_t &other) noexcept
Copy Assignment operator.
all units allocate invdividually in local memory and synchronize in epochs
void detach(pointer gptr, size_type num_local_elem)
Unregister local memory segment from global memory space.
DART Global pointer type.
Definition: dart_globmem.h:77
void deallocate(pointer gptr, size_type num_local_elem)
Deallocates a memory segment from global memory space.
#define DART_GPTR_ISNULL(gptr_)
Test for NULL global pointer.
Definition: dart_globmem.h:118
#define DART_GPTR_EQUAL(gptr1_, gptr2_)
Compare two global pointers.
Definition: dart_globmem.h:128
local_pointer allocate_local(size_type num_local_elem)
Allocates num_local_elem local elements in the active unit&#39;s local memory.
pointer allocate(size_type num_local_elem)
Allocates a global memory segment with at least num_local_elem bytes.
void deallocate_local(local_pointer lptr, size_type num_local_elem)
Deallocates memory segment in the active unit&#39;s local memory.
EpochSynchronizedAllocator(Team const &team, LMemSpace *r=nullptr) noexcept
Constructor.