YAKL
YAKL_allocators.h
Go to the documentation of this file.
1 
7 #pragma once
8 // Included by YAKL.h
9 
11 namespace yakl {
12 
16  inline bool use_pool() { return get_yakl_instance().pool_enabled; }
17 
18 
19  inline Gator & get_pool() { return get_yakl_instance().pool; }
20 
21 
22  // Set the allocation and deallocation functions for YAKL
24  inline void set_device_alloc_free(std::function<void *( size_t )> &alloc , std::function<void ( void * )> &dealloc) {
25  #if defined(YAKL_ARCH_CUDA)
26  #if defined (YAKL_MANAGED_MEMORY)
27  alloc = [] ( size_t bytes ) -> void* {
28  if (bytes == 0) return nullptr;
29  void *ptr;
30  cudaMallocManaged(&ptr,bytes); // Allocate managed memory
31  if (ptr == nullptr) yakl_throw("ERROR: cudaMallocManaged returned nullptr. You have likely run out of memory");
32  #ifdef _OPENMP45
33  // if using OMP target offload, make sure OMP runtime knows to leave this memory alone
34  omp_target_associate_ptr(ptr,ptr,bytes,0,0);
35  #endif
36  #ifdef _OPENACC
37  // if using OpenACC, make sure OpenACC runtime knows to leave this memory alone
38  acc_map_data(ptr,ptr,bytes);
39  #endif
41  return ptr;
42  };
43  dealloc = [] ( void *ptr ) {
44  cudaFree(ptr);
46  };
47  #else
48  alloc = [] ( size_t bytes ) -> void* {
49  if (bytes == 0) return nullptr;
50  void *ptr;
51  cudaMalloc(&ptr,bytes);
52  if (ptr == nullptr) yakl_throw("ERROR: cudaMalloc returned nullptr. You have likely run out of memory");
54  return ptr;
55  };
56  dealloc = [] ( void *ptr ) {
57  cudaFree(ptr);
59  };
60  #endif
61  #elif defined(YAKL_ARCH_HIP)
62  #if defined (YAKL_MANAGED_MEMORY)
63  alloc = [] ( size_t bytes ) -> void* {
64  if (bytes == 0) return nullptr;
65  void *ptr;
66  hipMallocManaged(&ptr,bytes); // This is the current standin for managed memory for HIP
67  if (ptr == nullptr) yakl_throw("ERROR: hipMallocManaged returned nullptr. You have likely run out of memory");
68  #ifdef _OPENMP45
69  // if using OMP target offload, make sure OMP runtime knows to leave this memory alone
70  omp_target_associate_ptr(ptr,ptr,bytes,0,0);
71  #endif
72  #ifdef _OPENACC
73  // if using OpenACC, make sure OpenACC runtime knows to leave this memory alone
74  acc_map_data(ptr,ptr,bytes);
75  #endif
77  return ptr;
78  };
79  dealloc = [] ( void *ptr ) {
80  hipFree(ptr);
82  };
83  #else
84  alloc = [] ( size_t bytes ) -> void* {
85  if (bytes == 0) return nullptr;
86  void *ptr;
87  hipMalloc(&ptr,bytes);
88  if (ptr == nullptr) yakl_throw("ERROR: hipMalloc returned nullptr. You have likely run out of memory");
90  return ptr;
91  };
92  dealloc = [] ( void *ptr ) {
93  hipFree(ptr);
95  };
96  #endif
97  #elif defined (YAKL_ARCH_SYCL)
98  #if defined (YAKL_MANAGED_MEMORY)
99  alloc = [] ( size_t bytes ) -> void* {
100  if (bytes == 0) return nullptr;
101  // Allocate unified shared memory
102  void *ptr = sycl::malloc_shared(bytes,sycl_default_stream());
103  if (ptr == nullptr) yakl_throw("ERROR: sycl::malloc_shared returned nullptr. You have likely run out of memory");
104  #ifdef _OPENMP45
105  // if using OMP target offload, make sure OMP runtime knows to leave this memory alone
106  omp_target_associate_ptr(ptr,ptr,bytes,0,0);
107  #endif
108  #ifdef _OPENACC
109  // if using OpenACC, make sure OpenACC runtime knows to leave this memory alone
110  acc_map_data(ptr,ptr,bytes);
111  #endif
112  return ptr;
113  };
114  dealloc = [] ( void *ptr ) {
115  sycl::free(ptr, sycl_default_stream());
117  };
118  #else
119  alloc = [] ( size_t bytes ) -> void* {
120  if (bytes == 0) return nullptr;
121  void *ptr = sycl::malloc_device(bytes,sycl_default_stream());
122  if (ptr == nullptr) yakl_throw("ERROR: sycl::malloc_device returned nullptr. You have likely run out of memory");
124  return ptr;
125  };
126  dealloc = [] ( void *ptr ) {
127  sycl::free(ptr, sycl_default_stream());
129  };
130  #endif
131  #else
132  alloc = [] ( size_t bytes ) -> void* {
133  if (bytes == 0) return nullptr;
134  void *ptr = ::malloc(bytes);
135  if (ptr == nullptr) yakl_throw("ERROR: malloc returned nullptr. You have likely run out of memory");
136  return ptr;
137  };
138  dealloc = [] ( void *ptr ) {
139  ::free(ptr);
140  };
141  #endif
142  }
143 
144 
151  fence();
152  if (use_pool()) {
153  get_yakl_instance().alloc_device_func = [] (size_t bytes , char const *label) -> void * {
154  #ifdef YAKL_MEMORY_DEBUG
155  if (yakl_mainproc()) std::cout << "MEMORY_DEBUG: Allocating label \"" << label << "\" of size " << bytes << " bytes" << std::endl;
156  #endif
157  void * ptr = get_yakl_instance().pool.allocate( bytes , label );
158  #ifdef YAKL_MEMORY_DEBUG
159  if (yakl_mainproc()) std::cout << "MEMORY_DEBUG: Successfully allocated label \"" << label
160  << " with pointer address " << ptr << std::endl;
161  #endif
162  return ptr;
163  };
164  get_yakl_instance().free_device_func = [] (void *ptr , char const *label) {
165  #ifdef YAKL_MEMORY_DEBUG
166  if (yakl_mainproc()) std::cout << "MEMORY_DEBUG: Freeing label \"" << label << "\" with pointer address " << ptr << std::endl;
167  #endif
168  get_yakl_instance().pool.free( ptr , label );
169  };
170  } else {
171  std::function<void *( size_t)> alloc;
172  std::function<void ( void *)> dealloc;
173  set_device_alloc_free(alloc , dealloc);
174  get_yakl_instance().alloc_device_func = [=] (size_t bytes , char const *label) -> void * {
175  #ifdef YAKL_MEMORY_DEBUG
176  if (yakl_mainproc()) std::cout << "MEMORY_DEBUG: Allocating label \"" << label << "\" of size " << bytes << " bytes" << std::endl;
177  #endif
178  void * ptr = alloc(bytes);
179  #ifdef YAKL_MEMORY_DEBUG
180  if (yakl_mainproc()) std::cout << "MEMORY_DEBUG: Successfully allocated label \"" << label
181  << " with pointer address " << ptr << std::endl;
182  #endif
183  return ptr;
184  };
185  get_yakl_instance().free_device_func = [=] (void *ptr , char const *label) {
186  #ifdef YAKL_MEMORY_DEBUG
187  if (yakl_mainproc()) std::cout << "MEMORY_DEBUG: Freeing label \"" << label << "\" with pointer address " << ptr << std::endl;
188  #endif
189  dealloc(ptr);
190  };
191  }
192 
193  get_yakl_instance().device_allocators_are_default = true;
194  }
195 
196 
204  inline void set_device_allocator ( std::function<void *(size_t)> func ) {
205  fence(); get_yakl_instance().alloc_device_func = [=] (size_t bytes , char const *label) -> void * { return func(bytes); };
206  get_yakl_instance().device_allocators_are_default = false;
207  }
208 
209 
214  inline void set_device_deallocator( std::function<void (void *)> func ) {
215  fence(); get_yakl_instance().free_device_func = [=] (void *ptr , char const *label) { func(ptr); };
216  get_yakl_instance().device_allocators_are_default = false;
217  }
218 
219 
224  inline void set_device_allocator ( std::function<void *( size_t , char const *)> func ) { fence(); get_yakl_instance().alloc_device_func = func; }
225 
226 
231  inline void set_device_deallocator( std::function<void ( void * , char const *)> func ) { fence(); get_yakl_instance().free_device_func = func; }
232 
234  inline void * alloc_device( size_t bytes, char const *label) { return get_yakl_instance().alloc_device_func(bytes,label); }
235 
237  inline void free_device ( void * ptr , char const *label) { get_yakl_instance().free_device_func (ptr ,label); }
238 
239 }
241 
242 
yakl::use_pool
bool use_pool()
If true, then the pool allocator is being used for all device allocations.
Definition: YAKL_allocators.h:16
__YAKL_NAMESPACE_WRAPPER_END__
#define __YAKL_NAMESPACE_WRAPPER_END__
Definition: YAKL.h:20
yakl::free_device
void free_device(void *ptr, char const *label)
Free on the device using YAKL's device deallocator.
Definition: YAKL_allocators.h:237
__YAKL_NAMESPACE_WRAPPER_BEGIN__
#define __YAKL_NAMESPACE_WRAPPER_BEGIN__
Definition: YAKL.h:19
yakl::Gator
YAKL Pool allocator class.
Definition: YAKL_Gator.h:26
yakl::set_device_allocator
void set_device_allocator(std::function< void *(size_t)> func)
Override YAKL's device allocator with the passed function (No Label).
Definition: YAKL_allocators.h:204
yakl::fence
void fence()
Block the host code until all device code has completed.
Definition: YAKL_fence.h:16
yakl::yakl_throw
YAKL_INLINE void yakl_throw(const char *msg)
Throw an error message. Works from the host or device.
Definition: YAKL_error.h:17
yakl::set_yakl_allocators_to_default
void set_yakl_allocators_to_default()
Return all YAKL allocators to their defaults.
Definition: YAKL_allocators.h:150
yakl::yakl_mainproc
bool yakl_mainproc()
If true, this is the main MPI process (task number == 0)
Definition: YAKL_error.h:64
yakl::set_device_deallocator
void set_device_deallocator(std::function< void(void *)> func)
Override YAKL's device deallocator with the passed function (No Label).
Definition: YAKL_allocators.h:214
yakl::alloc_device
void * alloc_device(size_t bytes, char const *label)
Allocate on the device using YAKL's device allocator.
Definition: YAKL_allocators.h:234
yakl
yakl::get_pool
Gator & get_pool()
Definition: YAKL_allocators.h:19
yakl::check_last_error
void check_last_error()
Checks to see if an error has occurred on the device.
Definition: YAKL_error.h:45