HAMR
The Heterogeneous Accelerator Memory Resource
hamr_openmp_allocator.h
1 #ifndef hamr_openmp_allocator_h
2 #define hamr_openmp_allocator_h
3 
4 #include "hamr_config.h"
5 #include "hamr_env.h"
6 
7 #include <iostream>
8 #include <type_traits>
9 #include <memory>
10 #include <typeinfo>
11 #include <cassert>
12 #include <cstring>
13 
14 #include <omp.h>
15 
16 namespace hamr
17 {
18 /// a deleter for arrays allocated with OpenMP
19 template <typename T, typename E = void>
20 class openmp_deleter {};
21 
22 /// a deleter for arrays allocated with OpenMP, specialized for objects
23 template <typename T>
24 class HAMR_EXPORT openmp_deleter<T, typename std::enable_if<!std::is_arithmetic<T>::value>::type>
25 {
26 public:
27  /** constructs the deleter
28  * @param[in] ptr the pointer to the array to delete
29  * @param[in] n the number of elements in the array
30  */
31  openmp_deleter(T *ptr, size_t n, int dev);
32 
33  /** deletes the array
34  * @param[in] ptr the pointer to the array to delete. must be the same as
35  * that passed during construction.
36  */
37  void operator()(T *ptr);
38 
39 private:
40  T *m_ptr;
41  size_t m_elem;
42  int m_dev;
43 };
44 
45 // --------------------------------------------------------------------------
46 template <typename T>
48  ::openmp_deleter(T *ptr, size_t n, int dev) : m_ptr(ptr), m_elem(n), m_dev(dev)
49 {
50 #if defined(HAMR_VERBOSE)
51  if (hamr::get_verbose())
52  {
53  std::cerr << "created openmp_deleter for array of " << n
54  << " objects of type " << typeid(T).name() << sizeof(T)
55  << " at " << m_ptr << " on device " << m_dev << std::endl;
56  }
57 #endif
58 }
59 
60 // --------------------------------------------------------------------------
61 template <typename T>
62 void
63 openmp_deleter<T, typename std::enable_if<!std::is_arithmetic<T>::value>::type>
64  ::operator()(T *ptr)
65 {
66  assert(ptr == m_ptr);
67 
68 #if defined(HAMR_VERBOSE)
69  if (hamr::get_verbose())
70  {
71  std::cerr << "openmp_deleter deleting array of " << m_elem
72  << " objects of type " << typeid(T).name() << sizeof(T)
73  << " at " << m_ptr << " on device " << m_dev << std::endl;
74  }
75 #endif
76 
77  // invoke the destructor
78  for (size_t i = 0; i < m_elem; ++i)
79  ptr[i].~T();
80 
81  // free the array
82  omp_target_free(ptr, m_dev);
83 }
84 
85 
86 
87 
88 
89 /// a deleter for arrays allocated with OpenMP, specialized for numbers
90 template <typename T>
91 class HAMR_EXPORT openmp_deleter<T, typename std::enable_if<std::is_arithmetic<T>::value>::type>
92 {
93 public:
94  /** constructs the deleter
95  * @param[in] ptr the pointer to the array to delete
96  * @param[in] n the number of elements in the array
97  */
98  openmp_deleter(T *ptr, size_t n, int dev);
99 
100  /** deletes the array
101  * @param[in] ptr the pointer to the array to delete. must be the same as
102  * that passed during construction.
103  */
104  void operator()(T *ptr);
105 
106 private:
107  T *m_ptr;
108  size_t m_elem;
109  int m_dev;
110 };
111 
112 // --------------------------------------------------------------------------
113 template <typename T>
115  ::openmp_deleter(T *ptr, size_t n, int dev) : m_ptr(ptr), m_elem(n), m_dev(dev)
116 {
117 #if defined(HAMR_VERBOSE)
118  if (hamr::get_verbose())
119  {
120  std::cerr << "created openmp_deleter for array of " << n
121  << " numbers of type " << typeid(T).name() << sizeof(T)
122  << " at " << m_ptr << " on device " << m_dev << std::endl;
123  }
124 #endif
125 }
126 
127 // --------------------------------------------------------------------------
128 template <typename T>
129 void
130 openmp_deleter<T, typename std::enable_if<std::is_arithmetic<T>::value>::type>
131  ::operator()(T *ptr)
132 {
133  assert(ptr == m_ptr);
134 
135 #if defined(HAMR_VERBOSE)
136  if (hamr::get_verbose())
137  {
138  std::cerr << "openmp_deleter deleting array of " << m_elem
139  << " numbers of type " << typeid(T).name() << sizeof(T)
140  << " at " << m_ptr << " on device " << m_dev << std::endl;
141  }
142 #endif
143 
144  // free the array
145  omp_target_free(ptr, m_dev);
146 }
147 
148 
149 
150 
151 
152 /// a class for allocating arrays with OpenMP
153 template <typename T, typename E = void>
155 
156 /// a class for allocating arrays with OpenMP, specialized for objects
157 template <typename T>
158 struct HAMR_EXPORT openmp_allocator<T, typename std::enable_if<!std::is_arithmetic<T>::value>::type>
159 {
160  /** allocate an array of n elements.
161  * @param[in] n the number of elements to allocate
162  * @returns a shared pointer to the array that holds a deleter for the memory
163  */
164  static std::shared_ptr<T> allocate(size_t n);
165 
166  /** allocate an array of n elements.
167  * @param[in] n the number of elements to allocate
168  * @param[in] val a value to initialize the elements to
169  * @returns a shared pointer to the array that holds a deleter for the memory
170  */
171 
172  static std::shared_ptr<T> allocate(size_t n, const T &val);
173 
174  /** allocate an array of n elements.
175  * @param[in] n the number of elements to allocate
176  * @param[in] vals an array of n elements to initialize the elements with
177  * @returns a shared pointer to the array that holds a deleter for the memory
178  */
179  template <typename U>
180  static std::shared_ptr<T> allocate(size_t n, const U *vals);
181 };
182 
183 // --------------------------------------------------------------------------
184 template <typename T>
185 std::shared_ptr<T>
187  ::allocate(size_t n)
188 {
189  // allocate
190  int dev = omp_get_default_device();
191  T *ptr = (T*)omp_target_alloc(n*sizeof(T), dev);
192 
193  // construct
194  #pragma omp target teams HAMR_OPENMP_LOOP is_device_ptr(ptr)
195  for (size_t i = 0; i < n; ++i)
196  new (&ptr[i]) T();
197 
198 #if defined(HAMR_VERBOSE)
199  if (hamr::get_verbose())
200  {
201  std::cerr << "openmp_allocator allocating array of " << n
202  << " objects of type " << typeid(T).name() << sizeof(T)
203  << " at " << ptr << " on device " << dev << std::endl;
204  }
205 #endif
206 
207  // package
208  return std::shared_ptr<T>(ptr, openmp_deleter<T>(ptr, n, dev));
209 }
210 
211 // --------------------------------------------------------------------------
212 template <typename T>
213 std::shared_ptr<T>
214 openmp_allocator<T, typename std::enable_if<!std::is_arithmetic<T>::value>::type>
215  ::allocate(size_t n, const T &val)
216 {
217  // allocate
218  int dev = omp_get_default_device();
219  T *ptr = (T*)omp_target_alloc(n*sizeof(T), dev);
220 
221  // construct
222  #pragma omp target teams HAMR_OPENMP_LOOP is_device_ptr(ptr) map(to: val)
223  for (size_t i = 0; i < n; ++i)
224  new (&ptr[i]) T(val);
225 
226 #if defined(HAMR_VERBOSE)
227  if (hamr::get_verbose())
228  {
229  std::cerr << "openmp_allocator allocating array of " << n
230  << " objects of type " << typeid(T).name() << sizeof(T)
231  << " at " << ptr << " initialized to " << val << std::endl;
232  }
233 #endif
234 
235  // package
236  return std::shared_ptr<T>(ptr, openmp_deleter<T>(ptr, n));
237 }
238 
239 // --------------------------------------------------------------------------
240 template <typename T>
241 template <typename U>
242 std::shared_ptr<T>
243 openmp_allocator<T, typename std::enable_if<!std::is_arithmetic<T>::value>::type>
244  ::allocate(size_t n, const U *vals)
245 {
246  // allocate
247  int dev = omp_get_default_device();
248  T *ptr = (T*)omp_target_alloc(n*sizeof(T), dev);
249 
250  // construct
251  #pragma omp target teams HAMR_OPENMP_LOOP is_device_ptr(ptr) map(to: vals[0:n])
252  for (size_t i = 0; i < n; ++i)
253  new (&ptr[i]) T(vals[i]);
254 
255 #if defined(HAMR_VERBOSE)
256  if (hamr::get_verbose())
257  {
258  std::cerr << "openmp_allocator allocating array of " << n
259  << " objects of type " << typeid(T).name() << sizeof(T)
260  << " initialized from array of objects of type "
261  << typeid(U).name() << sizeof(U) << " at " << vals
262  << " on device " << dev << std::endl;
263  }
264 #endif
265 
266  // package
267  return std::shared_ptr<T>(ptr, openmp_deleter<T>(ptr, n));
268 }
269 
270 
271 
272 
273 /// a class for allocating arrays with OpenMP, specialized for numbers
274 template <typename T>
275 struct HAMR_EXPORT openmp_allocator<T, typename std::enable_if<std::is_arithmetic<T>::value>::type>
276 {
277  /** allocate an array of n elements.
278  * @param[in] n the number of elements to allocate
279  * @returns a shared pointer to the array that holds a deleter for the memory
280  */
281  static std::shared_ptr<T> allocate(size_t n);
282 
283  /** allocate an array of n elements.
284  * @param[in] n the number of elements to allocate
285  * @param[in] val a value to initialize the elements to
286  * @returns a shared pointer to the array that holds a deleter for the memory
287  */
288  static std::shared_ptr<T> allocate(size_t n, const T &val);
289 
290  /** allocate an array of n elements.
291  * @param[in] n the number of elements to allocate
292  * @param[in] vals an array of n elements to initialize the elements with
293  * @returns a shared pointer to the array that holds a deleter for the memory
294  */
295  template <typename U>
296  static std::shared_ptr<T> allocate(size_t n, const U *vals);
297 };
298 
299 // --------------------------------------------------------------------------
300 template <typename T>
301 std::shared_ptr<T>
303  ::allocate(size_t n)
304 {
305  size_t n_bytes = n*sizeof(T);
306 
307  // allocate
308  int dev = omp_get_default_device();
309  T *ptr = (T*)omp_target_alloc(n_bytes, dev);
310 
311  // construct
312 #if defined(HAMR_INIT_ALLOC)
313  #pragma omp target teams HAMR_OPENMP_LOOP is_device_ptr(ptr)
314  for (size_t i = 0; i < n; ++i)
315  ptr[i] = T(0);
316 #endif
317 
318 #if defined(HAMR_VERBOSE)
319  if (hamr::get_verbose())
320  {
321  std::cerr << "openmp_allocator allocating array of " << n
322  << " numbers of type " << typeid(T).name() << sizeof(T)
323  << " at " << ptr << " on device " << dev << std::endl;
324  }
325 #endif
326 
327  // package
328  return std::shared_ptr<T>(ptr, openmp_deleter<T>(ptr, n, dev));
329 }
330 
331 // --------------------------------------------------------------------------
332 template <typename T>
333 std::shared_ptr<T>
334 openmp_allocator<T, typename std::enable_if<std::is_arithmetic<T>::value>::type>
335  ::allocate(size_t n, const T &val)
336 {
337  size_t n_bytes = n*sizeof(T);
338 
339  // allocate
340  int dev = omp_get_default_device();
341  T *ptr = (T*)omp_target_alloc(n_bytes, dev);
342 
343  // construct
344  #pragma omp target teams HAMR_OPENMP_LOOP is_device_ptr(ptr) map(to: val)
345  for (size_t i = 0; i < n; ++i)
346  ptr[i] = val;
347 
348 #if defined(HAMR_VERBOSE)
349  if (hamr::get_verbose())
350  {
351  std::cerr << "openmp_allocator allocating array of " << n
352  << " numbers of type " << typeid(T).name() << sizeof(T)
353  << " at " << ptr << " initialized to " << val << std::endl;
354  }
355 #endif
356 
357  // package
358  return std::shared_ptr<T>(ptr, openmp_deleter<T>(ptr, n, dev));
359 }
360 
361 // --------------------------------------------------------------------------
362 template <typename T>
363 template <typename U>
364 std::shared_ptr<T>
365 openmp_allocator<T, typename std::enable_if<std::is_arithmetic<T>::value>::type>
366  ::allocate(size_t n, const U *vals)
367 {
368  size_t n_bytes = n*sizeof(T);
369 
370  // allocate
371  int dev = omp_get_default_device();
372  T *ptr = (T*)omp_target_alloc(n_bytes, dev);
373 
374  // construct
375  #pragma omp target teams HAMR_OPENMP_LOOP is_device_ptr(ptr) map(to: vals[0:n])
376  for (size_t i = 0; i < n; ++i)
377  ptr[i] = vals[i];
378 
379 #if defined(HAMR_VERBOSE)
380  if (hamr::get_verbose())
381  {
382  std::cerr << "openmp_allocator allocating array of " << n
383  << " numbers of type " << typeid(T).name() << sizeof(T)
384  << " at " << ptr << " initialized from an array of numbers of type "
385  << typeid(U).name() << sizeof(U) << " at " << vals << std::endl;
386  }
387 #endif
388 
389  // package
390  return std::shared_ptr<T>(ptr, openmp_deleter<T>(ptr, n, dev));
391 }
392 
393 };
394 
395 #endif
hamr::openmp_allocator
a class for allocating arrays with OpenMP
Definition: hamr_openmp_allocator.h:154
hamr::get_verbose
constexpr HAMR_EXPORT int get_verbose()
returns the value of the HAMR_VERBOSE environment variable
Definition: hamr_env.h:14
hamr
heterogeneous accelerator memory resource
Definition: hamr_buffer.h:40
hamr::openmp_deleter
a deleter for arrays allocated with OpenMP
Definition: hamr_openmp_allocator.h:20