vSMC
vSMC: 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-2015, 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
33 #define VSMC_UTILITY_ALIGNED_MEMORY
34 
35 #include <vsmc/internal/config.h>
36 #include <vsmc/internal/assert.hpp>
37 
38 #include <cstddef>
39 #include <cstdlib>
40 #include <memory>
41 #include <new>
42 #include <type_traits>
43 #include <vector>
44 
45 #if VSMC_HAS_POSIX
46 #include <stdlib.h>
47 #elif defined(VSMC_MSVC)
48 #include <malloc.h>
49 #endif
50 
51 #if VSMC_HAS_TBB_MALLOC
52 #include <tbb/scalable_allocator.h>
53 #endif
54 
55 #if VSMC_HAS_MKL
56 #include <mkl_service.h>
57 #endif
58 
61 #ifndef VSMC_ALIGNED_MEMORY_TYPE
62 #if VSMC_HAS_TBB_MALLOC
63 #define VSMC_ALIGNED_MEMORY_TYPE ::vsmc::AlignedMemoryTBB
64 #elif VSMC_HAS_MKL
65 #define VSMC_ALIGNED_MEMORY_TYPE ::vsmc::AlignedMemoryMKL
66 #elif VSMC_HAS_POSIX || defined(VSMC_MSVC)
67 #define VSMC_ALIGNED_MEMORY_TYPE ::vsmc::AlignedMemorySYS
68 #else
69 #define VSMC_ALIGNED_MEMORY_TYPE ::vsmc::AlignedMemorySTD
70 #endif
71 #endif
72 
75 #ifndef VSMC_ALIGNMENT
76 #define VSMC_ALIGNMENT 32
77 #endif
78 
79 #define VSMC_STATIC_ASSERT_UTILITY_ALIGNED_MEMORY_POWER_OF_TWO(Alignment) \
80  VSMC_STATIC_ASSERT( \
81  (Alignment != 0 && (Alignment & (Alignment - 1)) == 0), \
82  "**AlignedAllocator** USED WITH Alignment NOT A POWER OF TWO")
83 
84 #define VSMC_STATIC_ASSERT_UTILITY_ALIGNED_MEMORY_SIZEOF_VOID(Alignemnt) \
85  VSMC_STATIC_ASSERT((Alignment >= sizeof(void *)), \
86  "**AlginedAllocator** USED WITH Alignment LESS THAN sizeof(void *)")
87 
88 #define VSMC_STATIC_ASSERT_UTILITY_ALIGNED_MEMORY \
89  VSMC_STATIC_ASSERT_UTILITY_ALIGNED_MEMORY_POWER_OF_TWO(Alignment); \
90  VSMC_STATIC_ASSERT_UTILITY_ALIGNED_MEMORY_SIZEOF_VOID(Alignment);
91 
92 #define VSMC_RUNTIME_ASSERT_UTILITY_ALIGNED_MEMORY_POWER_OF_TWO(alignment) \
93  VSMC_RUNTIME_ASSERT( \
94  (alignment != 0 && (alignment & (alignment - 1)) == 0), \
95  "**aligned_malloc** USED WITH ALIGNMENT NOT A POWER OF TWO")
96 
97 #define VSMC_RUNTIME_ASSERT_UTILITY_ALIGNED_MEMORY_SIZEOF_VOID(alignemnt) \
98  VSMC_RUNTIME_ASSERT((alignment >= sizeof(void *)), \
99  "**aligned_malloc** USED WITH ALIGNMENT LESS THAN sizeof(void *)")
100 
101 #define VSMC_RUNTIME_ASSERT_UTILITY_ALIGNED_MEMORY \
102  VSMC_RUNTIME_ASSERT_UTILITY_ALIGNED_MEMORY_POWER_OF_TWO(alignment); \
103  VSMC_RUNTIME_ASSERT_UTILITY_ALIGNED_MEMORY_SIZEOF_VOID(alignment);
104 
105 namespace vsmc
106 {
107 
115 {
116  public:
117  static void *aligned_malloc(std::size_t n, std::size_t alignment)
118  {
120 
121  if (n == 0)
122  return nullptr;
123 
124  void *orig_ptr = std::malloc(n + alignment + sizeof(void *));
125  if (orig_ptr == nullptr)
126  throw std::bad_alloc();
127 
128  uintptr_t address = reinterpret_cast<uintptr_t>(orig_ptr);
129  uintptr_t offset = alignment - (address + sizeof(void *)) % alignment;
130  void *ptr =
131  reinterpret_cast<void *>(address + offset + sizeof(void *));
132  void **orig = reinterpret_cast<void **>(address + offset);
133  *orig = orig_ptr;
134 
135  return ptr;
136  }
137 
138  static void aligned_free(void *ptr)
139  {
140  std::free(*reinterpret_cast<void **>(
141  reinterpret_cast<uintptr_t>(ptr) - sizeof(void *)));
142  }
143 }; // class AlignedMemmorySTD
144 
145 #if VSMC_HAS_POSIX
146 
154 {
155  public:
156  static void *aligned_malloc(std::size_t n, std::size_t alignment)
157  {
159 
160  if (n == 0)
161  return nullptr;
162 
163  void *ptr;
164  if (posix_memalign(&ptr, alignment, n) != 0)
165  throw std::bad_alloc();
166 
167  return ptr;
168  }
169 
170  static void aligned_free(void *ptr) { free(ptr); }
171 }; // class AlignedMallocSYS
172 
173 #elif defined(VSMC_MSVC)
174 
175 class AlignedMemorySYS
176 {
177  public:
178  static void *aligned_malloc(std::size_t n, std::size_t alignment)
179  {
181 
182  if (n == 0)
183  return nullptr;
184 
185  void *ptr = _aligned_malloc(n, alignment);
186  if (ptr == nullptr)
187  throw std::bad_alloc();
188 
189  return ptr;
190  }
191 
192  static void aligned_free(void *ptr) { _aligned_free(ptr); }
193 }; // class AlignedMemorySYS
194 
195 #endif // VSMC_HAS_POSIX
196 
197 #if VSMC_HAS_TBB_MALLOC
198 
203 {
204  public:
205  static void *aligned_malloc(std::size_t n, std::size_t alignment)
206  {
208 
209  if (n == 0)
210  return nullptr;
211 
212  void *ptr = scalable_aligned_malloc(n, alignment);
213  if (ptr == nullptr)
214  throw std::bad_alloc();
215 
216  return ptr;
217  }
218 
219  static void aligned_free(void *ptr) { scalable_aligned_free(ptr); }
220 }; // class AlignedMemoryTBB
221 
222 #endif // VSMC_HAS_TBB_MALLOC
223 
224 #if VSMC_HAS_MKL
225 
229 {
230  public:
231  static void *aligned_malloc(std::size_t n, std::size_t alignment)
232  {
234 
235  if (n == 0)
236  return nullptr;
237 
238  void *ptr = mkl_malloc(n, static_cast<int>(alignment));
239  if (ptr == nullptr)
240  throw std::bad_alloc();
241 
242  return ptr;
243  }
244 
245  static void aligned_free(void *ptr) { mkl_free(ptr); }
246 }; // class AlignedMemoryMKL
247 
248 #endif // VSMC_HAS_MKL
249 
253 
265 template <typename T, std::size_t Alignment = VSMC_ALIGNMENT,
266  typename Memory = AlignedMemory>
267 class AlignedAllocator : public std::allocator<T>
268 {
269  public:
270  using size_type = typename std::allocator<T>::size_type;
271  using pointer = typename std::allocator<T>::pointer;
272 
273  template <typename U>
274  class rebind
275  {
276  public:
278  }; // class rebind
279 
281 
283  : std::allocator<T>(other)
284  {
286  }
287 
288  template <typename U>
290  : std::allocator<T>(static_cast<std::allocator<U>>(other))
291  {
293  }
294 
296  const AlignedAllocator<T, Alignment, Memory> &) = default;
297 
299  : std::allocator<T>(std::move(other))
300  {
302  }
303 
304  template <typename U>
306  : std::allocator<T>(static_cast<std::allocator<U>>(std::move(other)))
307  {
309  }
310 
313 
315 
316  pointer allocate(size_type n, const void * = nullptr)
317  {
318  if (n == 0)
319  return nullptr;
320 
321  return static_cast<pointer>(
322  memory_.aligned_malloc(sizeof(T) * n, Alignment));
323  }
324 
326  {
327  if (ptr != nullptr)
328  memory_.aligned_free(ptr);
329  }
330 
331  private:
332  Memory memory_;
333 }; // class AlignedAllocator
334 
337 template <typename T>
338 using Allocator = typename std::conditional<std::is_scalar<T>::value,
339  AlignedAllocator<T>, std::allocator<T>>::type;
340 
343 template <typename T>
344 using AlignedVector = std::vector<T, AlignedAllocator<T>>;
345 
348 template <typename T>
349 using Vector = typename std::conditional<std::is_scalar<T>::value,
350  std::vector<T, AlignedAllocator<T>>, std::vector<T>>::type;
351 
352 } // namespace vsmc
353 
354 #endif // VSMC_UTILITY_ALIGNED_MEMORY
AlignedAllocator(AlignedAllocator< T, Alignment, Memory > &&other)
Definition: monitor.hpp:49
static void * aligned_malloc(std::size_t n, std::size_t alignment)
AlignedAllocator(AlignedAllocator< U, Alignment, Memory > &&other)
std::vector< T, AlignedAllocator< T >> AlignedVector
Vector type using AlignedAllocator.
Aligned memory using std::malloc and std::free
Aligned memory using Intel TBB scalable_aligned_malloc and scalable_aligned_free. ...
typename std::allocator< T >::size_type size_type
typename std::conditional< std::is_scalar< T >::value, std::vector< T, AlignedAllocator< T >>, std::vector< T >>::type Vector
AlignedVector for scalar type and std::vector for others.
static void aligned_free(void *ptr)
STL namespace.
#define VSMC_STATIC_ASSERT_UTILITY_ALIGNED_MEMORY
Aligned memory using Intel MKL mkl_malloc and mkl_free
#define VSMC_ALIGNMENT
Defualt alignment.
#define VSMC_RUNTIME_ASSERT_UTILITY_ALIGNED_MEMORY
static void * aligned_malloc(std::size_t n, std::size_t alignment)
static void aligned_free(void *ptr)
static void * aligned_malloc(std::size_t n, std::size_t alignment)
AlignedAllocator(const AlignedAllocator< T, Alignment, Memory > &other)
static void aligned_free(void *ptr)
Aligned memory using native system aligned memory allocation.
Aligned allocator.
typename std::allocator< T >::pointer pointer
AlignedAllocator(const AlignedAllocator< U, Alignment, Memory > &other)
typename std::conditional< std::is_scalar< T >::value, AlignedAllocator< T >, std::allocator< T >>::type Allocator
AlignedAllocator for scalar type and std::allocator for others.
static void * aligned_malloc(std::size_t n, std::size_t alignment)
pointer allocate(size_type n, const void *=nullptr)
static void aligned_free(void *ptr)
void deallocate(pointer ptr, size_type)
#define VSMC_ALIGNED_MEMORY_TYPE
Default AlignedMemory type.