vSMC  v3.0.0
Scalable Monte Carlo
aligned_memory.hpp
Go to the documentation of this file.
1 //============================================================================
2 // vSMC/include/vsmc/utility/aligned_memory.hpp
3 //----------------------------------------------------------------------------
4 // vSMC: Scalable Monte Carlo
5 //----------------------------------------------------------------------------
6 // Copyright (c) 2013-2016, Yan Zhou
7 // All rights reserved.
8 //
9 // Redistribution and use in source and binary forms, with or without
10 // modification, are permitted provided that the following conditions are met:
11 //
12 // Redistributions of source code must retain the above copyright notice,
13 // this list of conditions and the following disclaimer.
14 //
15 // Redistributions in binary form must reproduce the above copyright notice,
16 // this list of conditions and the following disclaimer in the documentation
17 // and/or other materials provided with the distribution.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS
20 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 // POSSIBILITY OF SUCH DAMAGE.
30 //============================================================================
31 
32 #ifndef VSMC_UTILITY_ALIGNED_MEMORY_HPP
33 #define VSMC_UTILITY_ALIGNED_MEMORY_HPP
34 
35 #include <vsmc/internal/basic.hpp>
36 
37 #if VSMC_HAS_POSIX
38 #include <stdlib.h>
39 #elif defined(VSMC_MSVC)
40 #include <malloc.h>
41 #endif
42 
43 #if VSMC_HAS_TBB
44 #include <tbb/scalable_allocator.h>
45 #endif
46 
49 #ifndef VSMC_ALIGNMENT
50 #define VSMC_ALIGNMENT 32
51 #endif
52 
55 #ifndef VSMC_ALIGNMENT_MIN
56 #define VSMC_ALIGNMENT_MIN 16
57 #endif
58 
59 #if VSMC_ALIGNMENT < VSMC_ALIGNMENT_MIN
60 #undef VSMC_ALIGNEMNT
61 #define VSMC_ALIGNMENT VSMC_ALIGNMENT_MIN
62 #endif
63 
66 #ifndef VSMC_ALIGNED_MEMORY_TYPE
67 #if VSMC_USE_TBB_MALLOC
68 #define VSMC_ALIGNED_MEMORY_TYPE ::vsmc::AlignedMemoryTBB
69 #elif VSMC_HAS_POSIX || defined(VSMC_MSVC)
70 #define VSMC_ALIGNED_MEMORY_TYPE ::vsmc::AlignedMemorySYS
71 #else
72 #define VSMC_ALIGNED_MEMORY_TYPE ::vsmc::AlignedMemorySTD
73 #endif
74 #endif
75 
77 #ifndef VSMC_CONSTRUCT_SCALAR
78 #define VSMC_CONSTRUCT_SCALAR 0
79 #endif
80 
90 #define VSMC_DEFINE_NEW_DELETE(Class) \
91  public: \
92  static void *operator new(std::size_t n) \
93  { \
94  void *ptr = ::vsmc::AlignedMemory::aligned_malloc( \
95  n, ::vsmc::AlignmentTrait<Class>::value); \
96  if (ptr == nullptr) \
97  throw std::bad_alloc(); \
98  \
99  return ptr; \
100  } \
101  \
102  static void *operator new[](std::size_t n) \
103  { \
104  void *ptr = ::vsmc::AlignedMemory::aligned_malloc( \
105  n, ::vsmc::AlignmentTrait<Class>::value); \
106  if (ptr == nullptr) \
107  throw std::bad_alloc(); \
108  \
109  return ptr; \
110  } \
111  \
112  static void *operator new(std::size_t, void *ptr) { return ptr; } \
113  \
114  static void *operator new[](std::size_t, void *ptr) { return ptr; } \
115  \
116  static void operator delete(void *ptr) \
117  { \
118  ::vsmc::AlignedMemory::aligned_free(ptr); \
119  } \
120  \
121  static void operator delete[](void *ptr) \
122  { \
123  ::vsmc::AlignedMemory::aligned_free(ptr); \
124  } \
125  \
126  static void operator delete(void *, void *) {} \
127  \
128  static void operator delete[](void *, void *) {}
129 
130 namespace vsmc
131 {
132 
133 namespace internal
134 {
135 
136 template <typename T, bool = std::is_scalar<T>::value>
138 {
139  public:
140  static constexpr std::size_t value =
141  alignof(T) > VSMC_ALIGNMENT_MIN ? alignof(T) : VSMC_ALIGNMENT_MIN;
142 }; // class AlignmentTraitImpl
143 
144 template <typename T>
145 class AlignmentTraitImpl<T, true>
146 {
147  public:
148  static constexpr std::size_t
149  value = alignof(T) > VSMC_ALIGNMENT ? alignof(T) : VSMC_ALIGNMENT;
150 }; // class AlignmentTraitImpl
151 
152 } // namespace vsmc::internal
153 
160 template <typename T>
161 class AlignmentTrait : public std::integral_constant<std::size_t,
162  internal::AlignmentTraitImpl<T>::value>
163 {
164 }; // class AlignmentTrait
165 
173 {
174  public:
175  static void *aligned_malloc(std::size_t n, std::size_t alignment) noexcept
176  {
177  std::size_t bytes = (n > 0 ? n : 1) + alignment + sizeof(void *);
178  if (bytes < n)
179  return nullptr;
180 
181  void *orig_ptr = std::malloc(bytes);
182  if (orig_ptr == nullptr)
183  return nullptr;
184 
185  uintptr_t address = reinterpret_cast<uintptr_t>(orig_ptr);
186  uintptr_t offset = alignment - (address + sizeof(void *)) % alignment;
187  void *ptr =
188  reinterpret_cast<void *>(address + offset + sizeof(void *));
189  void **orig = reinterpret_cast<void **>(address + offset);
190  *orig = orig_ptr;
191 
192  return ptr;
193  }
194 
195  static void aligned_free(void *ptr) noexcept
196  {
197  if (ptr != nullptr) {
198  std::free(*reinterpret_cast<void **>(
199  reinterpret_cast<uintptr_t>(ptr) - sizeof(void *)));
200  }
201  }
202 }; // class AlignedMemmorySTD
203 
204 #if VSMC_HAS_POSIX
205 
213 {
214  public:
215  static void *aligned_malloc(std::size_t n, std::size_t alignment) noexcept
216  {
217  void *ptr;
218  if (posix_memalign(&ptr, alignment, n > 0 ? n : 1) != 0)
219  return nullptr;
220  return ptr;
221  }
222 
223  static void aligned_free(void *ptr) noexcept
224  {
225  if (ptr != nullptr)
226  free(ptr);
227  }
228 }; // class AlignedMallocSYS
229 
230 #elif defined(VSMC_MSVC)
231 
232 class AlignedMemorySYS
233 {
234  public:
235  static void *aligned_malloc(std::size_t n, std::size_t alignment) noexcept
236  {
237  return _aligned_malloc(n > 0 ? n : 1, alignment);
238  }
239 
240  static void aligned_free(void *ptr) noexcept
241  {
242  if (ptr != nullptr)
243  _aligned_free(ptr);
244  }
245 }; // class AlignedMemorySYS
246 
247 #endif // VSMC_HAS_POSIX
248 
249 #if VSMC_HAS_TBB
250 
255 {
256  public:
257  static void *aligned_malloc(std::size_t n, std::size_t alignment) noexcept
258  {
259  return scalable_aligned_malloc(n > 0 ? n : 1, alignment);
260  }
261 
262  static void aligned_free(void *ptr) noexcept
263  {
264  if (ptr != nullptr)
265  scalable_aligned_free(ptr);
266  }
267 }; // class AlignedMemoryTBB
268 
269 #endif // VSMC_HAS_TBB
270 
274 
290 template <typename T, std::size_t Alignment = AlignmentTrait<T>::value,
291  typename Memory = AlignedMemory>
292 class Allocator : public std::allocator<T>
293 {
294  static_assert(Alignment != 0 && (Alignment & (Alignment - 1)) == 0,
295  "**Allocator** USED WITH Alignment OTHER THAN A POWER OF TWO "
296  "POSITIVE INTEGER");
297 
298  static_assert(Alignment >= sizeof(void *),
299  "**Allocator** USED WITH Alignment LESS THAN sizeof(void *)");
300 
301  public:
302  using value_type = T;
303  using size_type = std::size_t;
304  using difference_type = std::ptrdiff_t;
305  using pointer = T *;
306  using const_pointer = const T *;
307  using reference = typename std::add_lvalue_reference<T>::type;
308  using const_reference = typename std::add_lvalue_reference<const T>::type;
309  using is_always_equal = std::true_type;
310 
311  template <typename U>
312  class rebind
313  {
314  public:
316  }; // class rebind
317 
318  Allocator() = default;
319 
320  Allocator(const Allocator<T, Alignment, Memory> &) = default;
321 
323 
325  const Allocator<T, Alignment, Memory> &) = default;
326 
328  Allocator<T, Alignment, Memory> &&) = default;
329 
330  template <typename U>
332  : std::allocator<T>(static_cast<std::allocator<U>>(other))
333  {
334  }
335 
336  template <typename U>
338  : std::allocator<T>(std::move(static_cast<std::allocator<U>>(other)))
339  {
340  }
341 
342  pointer allocate(size_type n, const void * = nullptr)
343  {
344  n = std::max(n, static_cast<size_type>(1));
345  size_type bytes = n * sizeof(value_type);
346  if (bytes < n)
347  throw std::bad_alloc();
348 
349  pointer ptr =
350  static_cast<pointer>(Memory::aligned_malloc(bytes, Alignment));
351  if (ptr == nullptr)
352  throw std::bad_alloc();
353 
354  return ptr;
355  }
356 
357  void deallocate(pointer ptr, size_type = 0) noexcept
358  {
359  if (ptr != nullptr)
360  Memory::aligned_free(ptr);
361  }
362 
363  template <typename U>
364  void construct(U *ptr)
365  {
366  construct_dispatch(ptr,
367  std::integral_constant<bool, (VSMC_CONSTRUCT_SCALAR != 0 ||
368  !std::is_scalar<U>::value)>());
369  }
370 
371  template <typename U, typename Arg, typename... Args>
372  void constrct(U *ptr, Arg &&arg, Args &&... args)
373  {
374  std::allocator<T>::construct(
375  ptr, std::forward<Arg>(arg), std::forward<Args>(args)...);
376  }
377 
378  private:
379  template <typename U>
380  void construct_dispatch(U *ptr, std::true_type)
381  {
382  std::allocator<T>::construct(ptr);
383  }
384 
385  template <typename U>
386  void construct_dispatch(U *, std::false_type)
387  {
388  }
389 }; // class Allocator
390 
393 template <std::size_t Alignment, typename Memory>
394 class Allocator<void, Alignment, Memory>
395 {
396  using value_type = void;
397  using pointer = void *;
398  using const_pointer = const void *;
399 
400  template <class U>
401  struct rebind {
402  using other = Allocator<U, Alignment, Memory>;
403  };
404 }; // class Allocator
405 
408 template <std::size_t Alignment, typename Memory>
409 class Allocator<const void, Alignment, Memory>
410 {
411  using value_type = const void;
412  using pointer = const void *;
413  using const_pointer = const void *;
414 
415  template <class U>
416  struct rebind {
417  using other = Allocator<U, Alignment, Memory>;
418  };
419 }; // class Allocator
420 
423 template <typename T1, typename T2, std::size_t Alignment, typename Memory>
426 {
427  return true;
428 }
429 
432 template <typename T1, typename T2, std::size_t Alignment, typename Memory>
435 {
436  return false;
437 }
438 
439 namespace internal
440 {
441 
442 template <typename Alloc>
444  : public AlignmentTrait<typename std::allocator_traits<Alloc>::value_type>
445 {
446 }; // class AllocatorAlignemnt
447 
448 template <typename T, std::size_t Alignment, typename Memory>
449 class AllocatorAlignment<Allocator<T, Alignment, Memory>>
450  : public std::integral_constant<std::size_t, Alignment>
451 {
452 }; // class AllocatorAlignment
453 
454 } // namespace vsmc::internal
455 
458 template <typename T, typename Alloc = Allocator<T>>
459 using Vector = std::vector<T, Alloc>;
460 
463 template <typename T, std::size_t N,
464  std::size_t Alignment = AlignmentTrait<T>::value>
465 class alignas(Alignment) Array : public std::array<T, N>
466 {
467  static_assert(Alignment != 0 && (Alignment & (Alignment - 1)) == 0,
468  "**Array** USED WITH Alignment OTHER THAN A POWER OF TWO "
469  "POSITIVE INTEGER");
470 
471  static_assert(Alignment >= sizeof(void *),
472  "**Array** USED WITH Alignment LESS THAN sizeof(void *)");
473 }; // class Array
474 
475 } // namespace vsmc
476 
477 #endif // VSMC_UTILITY_ALIGNED_MEMORY_HPP
std::vector< T, Alloc > Vector
std::vector with Allocator as default allocator
Definition: monitor.hpp:48
Aligned memory using std::malloc and std::free
#define VSMC_ALIGNMENT_MIN
The minimum alignment for any type.
Aligned memory using Intel TBB scalable_aligned_malloc and scalable_aligned_free. ...
STL namespace.
Allocator(const Allocator< U, Alignment, Memory > &other)
static void aligned_free(void *ptr) noexcept
static void * aligned_malloc(std::size_t n, std::size_t alignment) noexcept
const T * const_pointer
void construct(U *ptr)
Alignment of a given type.
static constexpr std::size_t value
#define VSMC_ALIGNMENT
The default alignment for scalar type.
bool operator!=(const SingleParticle< T > &sp1, const SingleParticle< T > &sp2)
std::ptrdiff_t difference_type
typename std::add_lvalue_reference< T >::type reference
Aligned memory using native system aligned memory allocation.
static void * aligned_malloc(std::size_t n, std::size_t alignment) noexcept
void deallocate(pointer ptr, size_type=0) noexcept
#define VSMC_CONSTRUCT_SCALAR
Allocator::construct default behavior for scalar type.
std::true_type is_always_equal
bool operator==(const SingleParticle< T > &sp1, const SingleParticle< T > &sp2)
Allocator(Allocator< U, Alignment, Memory > &&other)
void constrct(U *ptr, Arg &&arg, Args &&...args)
static void * aligned_malloc(std::size_t n, std::size_t alignment) noexcept
#define VSMC_ALIGNED_MEMORY_TYPE
Default AlignedMemory type.
std::array with proper alignment
static void aligned_free(void *ptr) noexcept
static void aligned_free(void *ptr) noexcept
std::size_t size_type
Aligned allocator.
pointer allocate(size_type n, const void *=nullptr)
typename std::add_lvalue_reference< const T >::type const_reference