Go to the documentation of this file.
9 #include "YAKL_LinearAllocator.h"
29 std::string pool_name;
31 std::list<LinearAllocator> pools;
33 std::function<
void *( size_t )> mymalloc;
35 std::function<void(
void * )> myfree;
37 std::function<void(
void *,
size_t )> myzero;
43 std::string error_message_cannot_grow;
45 std::string error_message_out_of_memory;
47 size_t high_water_mark;
49 size_t bytes_currently_allocated;
56 void die(std::string str=
"") {
57 std::cerr << str << std::endl;
58 throw std::runtime_error(str);
111 void init(std::function<
void *(
size_t )> mymalloc = [] (
size_t bytes) ->
void * { return ::malloc(bytes); },
112 std::function<void(
void * )> myfree = [] (
void *ptr) {
::free(ptr); } ,
113 std::function<void(
void *,
size_t )> myzero = [] (
void *ptr,
size_t bytes) {} ,
114 size_t initialSize = 1024*1024*1024 ,
115 size_t growSize = 1024*1024*1024 ,
116 size_t blockSize = 16*
sizeof(size_t) ,
117 std::string pool_name =
"Gator" ,
118 std::string error_message_out_of_memory =
"" ,
119 std::string error_message_cannot_grow =
"" ) {
120 this->mymalloc = mymalloc ;
121 this->myfree = myfree ;
122 this->myzero = myzero ;
123 this->growSize = growSize ;
124 this->blockSize = blockSize;
125 this->pool_name = pool_name;
126 this->error_message_out_of_memory = error_message_out_of_memory;
127 this->error_message_cannot_grow = error_message_cannot_grow ;
128 this->high_water_mark = 0;
129 this->bytes_currently_allocated = 0;
132 pools.push_back( LinearAllocator( initialSize , blockSize , mymalloc , myfree , myzero ,
133 pool_name , error_message_out_of_memory) );
140 if (pools.size() > 0) {
143 #ifdef YAKL_ARCH_SYCL
149 pools = std::list<LinearAllocator>();
151 bytes_currently_allocated = 0;
161 for (
auto it = pools.begin() ; it != pools.end() ; it++) {
162 it->printAllocsLeft();
175 void *
allocate(
size_t bytes,
char const * label=
"") {
176 if (bytes == 0)
return nullptr;
179 bool room_found =
false;
180 bool linear_bug =
false;
187 for (
auto it = pools.begin() ; it != pools.end() ; it++) {
188 if (it->iGotRoom(bytes)) {
189 ptr = it->allocate(bytes,label);
191 if (ptr ==
nullptr) linear_bug =
true;
197 if (bytes > growSize) {
198 std::cerr <<
"ERROR: For the pool allocator labeled \"" << pool_name <<
"\":" << std::endl;
199 std::cerr <<
"ERROR: Trying to allocate " << bytes <<
" bytes (" << bytes/1024./1024./1024. <<
" GB), "
200 <<
"but the current pool is too small, and growSize is only "
201 << growSize <<
" bytes (" << growSize/1024./1024./1024. <<
" GB). \nThus, the allocation will never fit in pool memory.\n";
202 std::cerr <<
"This can happen for a number of reasons. \nCheck the size of the variable being allocated in the "
203 <<
"line above and see if it's what you expected. \nIf it's absurdly large, then you might have tried "
204 <<
"to pass in a negative value for the size, or the size got corrupted somehow. \nNOTE: If you compiled "
205 <<
"for the wrong GPU artchitecture, it sometimes shows up here as well. \nIf the size of the variable "
206 <<
"is realistic, then you should increase the initial pool size and probably the grow size as "
207 <<
"well. \nWhen individual variables consume sizable percentages of a pool, memory gets fragmented, and "
208 <<
"the pool space isn't used efficiently. \nLarger pools will improve that. "
209 <<
"\nIn the extreme, you could create "
210 <<
"an initial pool that consumes most of the avialable device memory. \nIf that still doesn't work, then "
211 <<
"it sounds like you're choosing a problem size that's too large for the number of compute "
212 <<
"nodes you're using.\n";
213 std::cerr << error_message_cannot_grow << std::endl;
217 pools.push_back( LinearAllocator( growSize , blockSize , mymalloc , myfree , myzero ,
218 pool_name , error_message_out_of_memory) );
219 ptr = pools.back().allocate(bytes,label);
221 bytes_currently_allocated += ( (bytes-1)/blockSize+1 )*blockSize;
222 high_water_mark = std::max( high_water_mark , bytes_currently_allocated );
226 std::cerr <<
"ERROR: For the pool allocator labeled \"" << pool_name <<
"\":" << std::endl;
227 die(
"ERROR: It looks like you've found a bug in LinearAllocator. Please report this at github.com/mrnorman/YAKL");
229 if (ptr !=
nullptr) {
232 std::cerr <<
"ERROR: For the pool allocator labeled \"" << pool_name <<
"\":" << std::endl;
233 std::cerr <<
"Unable to allocate pointer. It looks like you might have run out of memory.";
234 die( error_message_out_of_memory );
242 void free(
void *ptr ,
char const * label =
"" ) {
243 bool pointer_valid =
false;
248 for (
auto it = pools.rbegin() ; it != pools.rend() ; it++) {
249 if (it->thisIsMyPointer(ptr)) {
250 size_t bytes = it->free(ptr,label);
251 bytes_currently_allocated -= bytes;
252 pointer_valid =
true;
258 if (!pointer_valid) {
259 std::cerr <<
"ERROR: For the pool allocator labeled \"" << pool_name <<
"\":" << std::endl;
260 std::cerr <<
"ERROR: Trying to free an invalid pointer\n";
261 die(
"This means you have either already freed the pointer, or its address has been corrupted somehow.");
271 for (
int ind_event_in=0; ind_event_in < events_in.size(); ind_event_in++) {
272 bool add_new_event =
true;
273 for (
int ind_event_list=0; ind_event_list <
waiting_events.size(); ind_event_list++) {
274 if (events_in[ind_event_in] ==
waiting_events[ind_event_list]) add_new_event =
false;
276 if (add_new_event)
waiting_events.push_back( events_in[ind_event_in] );
290 if (waiting_event.completed()) {
291 auto &completed_event = waiting_event;
296 for (
int i=0; i < waiting_entry.events.size(); i++) {
297 if (waiting_entry.events[i] == completed_event) waiting_entry.events.erase(waiting_entry.events.begin()+i);
301 if (waiting_entry.events.empty()) {
302 this->
free( waiting_entry.ptr , waiting_entry.label.c_str() );
317 for (
auto it = pools.begin() ; it != pools.end() ; it++) { sz += it->poolSize(); }
325 for (
auto it = pools.begin() ; it != pools.end() ; it++) { allocs += it->numAllocs(); }
340 return bytes_currently_allocated;
void free_completed_waiting_entries()
Check all deallcation entries that are waiting on stream events to see if those events have completed...
Definition: YAKL_Gator.h:284
Gator()
Please use the init() function to specify parameters, not the constructor.
Definition: YAKL_Gator.h:75
size_t get_num_allocs() const
Get the total number of allocations in all of the pools put together.
Definition: YAKL_Gator.h:323
double get_pool_high_water_space_efficiency() const
Get the proportion of total capacity among pools that has been allocated at this largest past memory ...
Definition: YAKL_Gator.h:351
~Gator()
All pools are automatically finalized when a Gator object is destroyed.
Definition: YAKL_Gator.h:91
Definition: YAKL_Gator.h:62
Gator & operator=(Gator &&)
A Gator object may be moved but not copied.
std::mutex mtx2
Definition: YAKL_Gator.h:53
std::vector< Event > events
Definition: YAKL_Gator.h:65
#define __YAKL_NAMESPACE_WRAPPER_END__
Definition: YAKL.h:20
void * allocate(size_t bytes, char const *label="")
Allocate the requested number of bytes using the requested label, and return the pointer to allocated...
Definition: YAKL_Gator.h:175
#define __YAKL_NAMESPACE_WRAPPER_BEGIN__
Definition: YAKL.h:19
size_t get_bytes_currently_allocated() const
Get the current number of bytes that have been allocated in the pools (this is actual allocation,...
Definition: YAKL_Gator.h:339
int get_num_pools() const
Get the current number of pools that have been allocated.
Definition: YAKL_Gator.h:335
YAKL Pool allocator class.
Definition: YAKL_Gator.h:26
void fence()
Block the host code until all device code has completed.
Definition: YAKL_fence.h:16
void free_with_event_dependencies(void *ptr, std::vector< Event > events_in, char const *label="")
Free the passed pointer, and return the pointer to allocated space.
Definition: YAKL_Gator.h:268
size_t get_high_water_mark() const
Get the current memory high water mark in bytes for all allocations passing through the pool.
Definition: YAKL_Gator.h:331
std::string label
Definition: YAKL_Gator.h:63
void finalize()
Finalize the pool allocator, deallocate all individual pools.
Definition: YAKL_Gator.h:139
void * ptr
Definition: YAKL_Gator.h:64
bool yakl_mainproc()
If true, this is the main MPI process (task number == 0)
Definition: YAKL_error.h:64
std::vector< Event > waiting_events
Definition: YAKL_Gator.h:69
void free(void *ptr, char const *label="")
Free the passed pointer, and return the pointer to allocated space.
Definition: YAKL_Gator.h:242
double get_pool_space_efficiency() const
Get the current proportion of total capacity among pools that is actually allocated.
Definition: YAKL_Gator.h:345
std::vector< WaitEntry > waiting_entries
Definition: YAKL_Gator.h:68
size_t get_pool_capacity() const
Get the total capacity of all of the pools put together.
Definition: YAKL_Gator.h:315
void init(std::function< void *(size_t)> mymalloc=[](size_t bytes) -> void *{ return ::malloc(bytes);}, std::function< void(void *)> myfree=[](void *ptr) { ::free(ptr);}, std::function< void(void *, size_t)> myzero=[](void *ptr, size_t bytes) {}, size_t initialSize=1024 *1024 *1024, size_t growSize=1024 *1024 *1024, size_t blockSize=16 *sizeof(size_t), std::string pool_name="Gator", std::string error_message_out_of_memory="", std::string error_message_cannot_grow="")
Initialize the pool.
Definition: YAKL_Gator.h:111
void printAllocsLeft()
[USEFUL FOR DEBUGGING] Print all allocations left in this pool object.
Definition: YAKL_Gator.h:159