Halide
block_allocator.h
Go to the documentation of this file.
1 #ifndef HALIDE_RUNTIME_BLOCK_ALLOCATOR_H
2 #define HALIDE_RUNTIME_BLOCK_ALLOCATOR_H
3 
4 #include "../HalideRuntime.h"
5 #include "../printer.h"
6 #include "linked_list.h"
7 #include "memory_resources.h"
8 #include "region_allocator.h"
9 
10 namespace Halide {
11 namespace Runtime {
12 namespace Internal {
13 
14 // --
15 
16 /** Allocator class interface for managing large contiguous blocks
17  * of memory, which are then sub-allocated into smaller regions of
18  * memory. This class only manages the address creation for the
19  * regions -- allocation callback functions are used to request the
20  * memory from the necessary system or API calls. This class is
21  * intended to be used inside of a higher level memory management
22  * class that provides thread safety, policy management and API
23  * integration for a specific runtime API (eg Vulkan, OpenCL, etc)
24  */
26 public:
27  // disable copy constructors and assignment
28  BlockAllocator(const BlockAllocator &) = delete;
29  BlockAllocator &operator=(const BlockAllocator &) = delete;
30 
31  // disable non-factory based construction
32  BlockAllocator() = delete;
33  ~BlockAllocator() = delete;
34 
35  // Allocators for the different types of memory we need to allocate
40  };
41 
42  // Runtime configuration parameters to adjust the behaviour of the block allocator
43  struct Config {
44  size_t initial_capacity = 0;
45  size_t maximum_pool_size = 0; //< Maximum number of bytes to allocate for the entire pool (including all blocks). Specified in bytes. Zero means no constraint
46  size_t minimum_block_size = 0; //< Minimum block size in bytes. Zero mean no constraint.
47  size_t maximum_block_size = 0; //< Maximum block size in bytes. Zero means no constraint
48  size_t maximum_block_count = 0; //< Maximum number of blocks to allocate. Zero means no constraint
49  size_t nearest_multiple = 0; //< Always round up the requested region sizes to the given integer value. Zero means no constraint
50  };
51 
52  // Factory methods for creation / destruction
53  static BlockAllocator *create(void *user_context, const Config &config, const MemoryAllocators &allocators);
54  static void destroy(void *user_context, BlockAllocator *block_allocator);
55 
56  // Public interface methods
57  MemoryRegion *reserve(void *user_context, const MemoryRequest &request);
58  int release(void *user_context, MemoryRegion *region); //< unmark and cache the region for reuse
59  int reclaim(void *user_context, MemoryRegion *region); //< free the region and consolidate
60  int retain(void *user_context, MemoryRegion *region); //< retain the region and increase the usage count
61  bool collect(void *user_context); //< returns true if any blocks were removed
62  int release(void *user_context);
63  int destroy(void *user_context);
64 
65  // Access methods
66  const MemoryAllocators &current_allocators() const;
67  const Config &current_config() const;
68  const Config &default_config() const;
69  size_t block_count() const;
70  size_t pool_size() const;
71 
72 private:
73  // Linked-list for storing the block resources
75 
76  // Initializes a new instance
77  void initialize(void *user_context, const Config &config, const MemoryAllocators &allocators);
78 
79  // Reserves a region of memory using the given allocator for the given block resource, returns nullptr on failure
80  MemoryRegion *reserve_memory_region(void *user_context, RegionAllocator *allocator, const MemoryRequest &request);
81 
82  // Creates a new region allocator for the given block resource
83  RegionAllocator *create_region_allocator(void *user_context, BlockResource *block);
84 
85  // Destroys the given region allocator and all associated memory regions
86  int destroy_region_allocator(void *user_context, RegionAllocator *region_allocator);
87 
88  // Reserves a block of memory for the requested size and returns the corresponding block entry, or nullptr on failure
89  BlockEntry *reserve_block_entry(void *user_context, const MemoryProperties &properties, size_t size, bool dedicated);
90 
91  // Locates the "best-fit" block entry for the requested size, or nullptr if none was found
92  BlockEntry *find_block_entry(void *user_context, const MemoryProperties &properties, size_t size, bool dedicated);
93 
94  // Creates a new block entry and int the list
95  BlockEntry *create_block_entry(void *user_context, const MemoryProperties &properties, size_t size, bool dedicated);
96 
97  // Releases the block entry from being used, and makes it available for further allocations
98  int release_block_entry(void *user_context, BlockEntry *block_entry);
99 
100  // Destroys the block entry and removes it from the list
101  int destroy_block_entry(void *user_context, BlockEntry *block_entry);
102 
103  // Invokes the allocation callback to allocate memory for the block region
104  int alloc_memory_block(void *user_context, BlockResource *block);
105 
106  // Invokes the deallocation callback to free memory for the memory block
107  int free_memory_block(void *user_context, BlockResource *block);
108 
109  // Returns a constrained size for the requested size based on config parameters
110  size_t constrain_requested_size(size_t size) const;
111 
112  // Returns true if the given block is compatible with the given properties
113  bool is_compatible_block(const BlockResource *block, const MemoryProperties &properties) const;
114 
115  // Returns true if the given block is suitable for the request allocation
116  bool is_block_suitable_for_request(void *user_context, const BlockResource *block, const MemoryProperties &properties, size_t size, bool dedicated) const;
117 
118  Config config;
119  LinkedList block_list;
120  MemoryAllocators allocators;
121 };
122 
123 BlockAllocator *BlockAllocator::create(void *user_context, const Config &cfg, const MemoryAllocators &allocators) {
124  halide_abort_if_false(user_context, allocators.system.allocate != nullptr);
125  BlockAllocator *result = reinterpret_cast<BlockAllocator *>(
126  allocators.system.allocate(user_context, sizeof(BlockAllocator)));
127 
128  if (result == nullptr) {
129  error(user_context) << "BlockAllocator: Failed to create instance! Out of memory!\n";
130  return nullptr;
131  }
132 
133  result->initialize(user_context, cfg, allocators);
134  return result;
135 }
136 
137 void BlockAllocator::destroy(void *user_context, BlockAllocator *instance) {
138  halide_abort_if_false(user_context, instance != nullptr);
139  const MemoryAllocators &allocators = instance->allocators;
140  instance->destroy(user_context);
141  halide_abort_if_false(user_context, allocators.system.deallocate != nullptr);
142  allocators.system.deallocate(user_context, instance);
143 }
144 
145 void BlockAllocator::initialize(void *user_context, const Config &cfg, const MemoryAllocators &ma) {
146  config = cfg;
147  allocators = ma;
148  block_list.initialize(user_context,
149  sizeof(BlockResource),
150  config.initial_capacity,
151  allocators.system);
152 }
153 
154 MemoryRegion *BlockAllocator::reserve(void *user_context, const MemoryRequest &request) {
155 #ifdef DEBUG_RUNTIME_INTERNAL
156  debug(user_context) << "BlockAllocator: Reserve ("
157  << "user_context=" << (void *)(user_context) << " "
158  << "offset=" << (uint32_t)request.offset << " "
159  << "size=" << (uint32_t)request.size << " "
160  << "dedicated=" << (request.dedicated ? "true" : "false") << " "
161  << "usage=" << halide_memory_usage_name(request.properties.usage) << " "
162  << "caching=" << halide_memory_caching_name(request.properties.caching) << " "
163  << "visibility=" << halide_memory_visibility_name(request.properties.visibility) << ") ...\n";
164 #endif
165  BlockEntry *block_entry = reserve_block_entry(user_context, request.properties, request.size, request.dedicated);
166  if (block_entry == nullptr) {
167  error(user_context) << "BlockAllocator: Failed to allocate new empty block of requested size ("
168  << (int32_t)(request.size) << " bytes)!\n";
169  return nullptr;
170  }
171 
172  BlockResource *block = static_cast<BlockResource *>(block_entry->value);
173  halide_abort_if_false(user_context, block != nullptr);
174  halide_abort_if_false(user_context, block->allocator != nullptr);
175 
176  MemoryRegion *result = reserve_memory_region(user_context, block->allocator, request);
177  if (result == nullptr) {
178 
179  // Unable to reserve region in an existing block ... create a new block and try again.
180  block_entry = create_block_entry(user_context, request.properties, request.size, request.dedicated);
181  if (block_entry == nullptr) {
182  error(user_context) << "BlockAllocator: Out of memory! Failed to allocate empty block of size ("
183  << (int32_t)(request.size) << " bytes)!\n";
184  return nullptr;
185  }
186 
187  block = static_cast<BlockResource *>(block_entry->value);
188  if (block->allocator == nullptr) {
189  block->allocator = create_region_allocator(user_context, block);
190  }
191 
192  result = reserve_memory_region(user_context, block->allocator, request);
193  }
194  return result;
195 }
196 
197 int BlockAllocator::release(void *user_context, MemoryRegion *memory_region) {
198  if (memory_region == nullptr) {
200  }
201  RegionAllocator *allocator = RegionAllocator::find_allocator(user_context, memory_region);
202  if (allocator == nullptr) {
204  }
205  return allocator->release(user_context, memory_region);
206 }
207 
208 int BlockAllocator::reclaim(void *user_context, MemoryRegion *memory_region) {
209  if (memory_region == nullptr) {
211  }
212  RegionAllocator *allocator = RegionAllocator::find_allocator(user_context, memory_region);
213  if (allocator == nullptr) {
215  }
216  return allocator->reclaim(user_context, memory_region);
217 }
218 
219 int BlockAllocator::retain(void *user_context, MemoryRegion *memory_region) {
220  if (memory_region == nullptr) {
222  }
223  RegionAllocator *allocator = RegionAllocator::find_allocator(user_context, memory_region);
224  if (allocator == nullptr) {
226  }
227  return allocator->retain(user_context, memory_region);
228 }
229 
230 bool BlockAllocator::collect(void *user_context) {
231  bool result = false;
232  BlockEntry *block_entry = block_list.back();
233  while (block_entry != nullptr) {
234  BlockEntry *prev_entry = block_entry->prev_ptr;
235  const BlockResource *block = static_cast<BlockResource *>(block_entry->value);
236  if (block->allocator == nullptr) {
237  block_entry = prev_entry;
238  continue;
239  }
240 
241 #ifdef DEBUG_RUNTIME_INTERNAL
242  uint64_t reserved = block->reserved;
243 #endif
244 
245  bool collected = block->allocator->collect(user_context);
246  if (collected) {
247 #ifdef DEBUG_RUNTIME_INTERNAL
248  debug(user_context) << "Collected block ("
249  << "block=" << (void *)block << " "
250  << "reserved=" << (uint32_t)block->reserved << " "
251  << "recovered=" << (uint32_t)(reserved - block->reserved) << " "
252  << ")\n";
253 #endif
254  }
255  if (block->reserved == 0) {
256  destroy_block_entry(user_context, block_entry);
257  result = true;
258  }
259 
260  block_entry = prev_entry;
261  }
262  return result;
263 }
264 
265 int BlockAllocator::release(void *user_context) {
266  BlockEntry *block_entry = block_list.back();
267  while (block_entry != nullptr) {
268  BlockEntry *prev_entry = block_entry->prev_ptr;
269  release_block_entry(user_context, block_entry);
270  block_entry = prev_entry;
271  }
272  return 0;
273 }
274 
275 int BlockAllocator::destroy(void *user_context) {
276  BlockEntry *block_entry = block_list.back();
277  while (block_entry != nullptr) {
278  BlockEntry *prev_entry = block_entry->prev_ptr;
279  destroy_block_entry(user_context, block_entry);
280  block_entry = prev_entry;
281  }
282  block_list.destroy(user_context);
283  return 0;
284 }
285 
286 MemoryRegion *BlockAllocator::reserve_memory_region(void *user_context, RegionAllocator *allocator, const MemoryRequest &request) {
287  MemoryRegion *result = allocator->reserve(user_context, request);
288  if (result == nullptr) {
289 #ifdef DEBUG_RUNTIME_INTERNAL
290  debug(user_context) << "BlockAllocator: Failed to allocate region of size ("
291  << (int32_t)(request.size) << " bytes)!\n";
292 #endif
293  // allocator has enough free space, but not enough contiguous space
294  // -- collect and try to reallocate
295  if (allocator->collect(user_context)) {
296  result = allocator->reserve(user_context, request);
297  }
298  }
299  return result;
300 }
301 
302 bool BlockAllocator::is_block_suitable_for_request(void *user_context, const BlockResource *block, const MemoryProperties &properties, size_t size, bool dedicated) const {
303  if (!is_compatible_block(block, properties)) {
304 #ifdef DEBUG_RUNTIME_INTERNAL
305  debug(user_context) << "BlockAllocator: skipping block ... incompatible properties!\n"
306  << " block_resource=" << (void *)block << "\n"
307  << " block_size=" << (uint32_t)block->memory.size << "\n"
308  << " block_reserved=" << (uint32_t)block->reserved << "\n"
309  << " block_usage=" << halide_memory_usage_name(block->memory.properties.usage) << "\n"
310  << " block_caching=" << halide_memory_caching_name(block->memory.properties.caching) << "\n"
311  << " block_visibility=" << halide_memory_visibility_name(block->memory.properties.visibility) << "\n";
312  debug(user_context) << " request_size=" << (uint32_t)size << "\n"
313  << " request_usage=" << halide_memory_usage_name(properties.usage) << "\n"
314  << " request_caching=" << halide_memory_caching_name(properties.caching) << "\n"
315  << " request_visibility=" << halide_memory_visibility_name(properties.visibility) << "\n";
316 #endif
317  // skip blocks that are using incompatible memory
318  return false;
319  }
320 
321  if (dedicated && (block->reserved > 0)) {
322 #ifdef DEBUG_RUNTIME_INTERNAL
323  debug(user_context) << "BlockAllocator: skipping block ... can be used for dedicated allocation!\n"
324  << " block_resource=" << (void *)block << "\n"
325  << " block_size=" << (uint32_t)block->memory.size << "\n"
326  << " block_reserved=" << (uint32_t)block->reserved << "\n";
327 #endif
328  // skip blocks that can't be dedicated to a single allocation
329  return false;
330 
331  } else if (block->memory.dedicated && (block->reserved > 0)) {
332 #ifdef DEBUG_RUNTIME_INTERNAL
333  debug(user_context) << "BlockAllocator: skipping block ... already dedicated to an allocation!\n"
334  << " block_resource=" << (void *)block << "\n"
335  << " block_size=" << (uint32_t)block->memory.size << "\n"
336  << " block_reserved=" << (uint32_t)block->reserved << "\n";
337 #endif
338  // skip dedicated blocks that are already allocated
339  return false;
340  }
341 
342  size_t available = (block->memory.size - block->reserved);
343  if (available >= size) {
344  return true;
345  }
346 
347  return false;
348 }
349 
350 BlockAllocator::BlockEntry *
351 BlockAllocator::find_block_entry(void *user_context, const MemoryProperties &properties, size_t size, bool dedicated) {
352  BlockEntry *block_entry = block_list.back();
353  while (block_entry != nullptr) {
354  BlockEntry *prev_entry = block_entry->prev_ptr;
355  const BlockResource *block = static_cast<BlockResource *>(block_entry->value);
356  if (is_block_suitable_for_request(user_context, block, properties, size, dedicated)) {
357 #ifdef DEBUG_RUNTIME_INTERNAL
358  debug(user_context) << "BlockAllocator: found suitable block ...\n"
359  << " user_context=" << (void *)(user_context) << "\n"
360  << " block_resource=" << (void *)block << "\n"
361  << " block_size=" << (uint32_t)block->memory.size << "\n"
362  << " block_reserved=" << (uint32_t)block->reserved << "\n"
363  << " request_size=" << (uint32_t)size << "\n"
364  << " dedicated=" << (dedicated ? "true" : "false") << "\n"
365  << " usage=" << halide_memory_usage_name(properties.usage) << "\n"
366  << " caching=" << halide_memory_caching_name(properties.caching) << "\n"
367  << " visibility=" << halide_memory_visibility_name(properties.visibility) << "\n";
368 #endif
369  return block_entry;
370  }
371  block_entry = prev_entry;
372  }
373 
374  if (block_entry == nullptr) {
375 #ifdef DEBUG_RUNTIME_INTERNAL
376  debug(user_context) << "BlockAllocator: couldn't find suitable block!\n"
377  << " user_context=" << (void *)(user_context) << "\n"
378  << " request_size=" << (uint32_t)size << "\n"
379  << " dedicated=" << (dedicated ? "true" : "false") << "\n"
380  << " usage=" << halide_memory_usage_name(properties.usage) << "\n"
381  << " caching=" << halide_memory_caching_name(properties.caching) << "\n"
382  << " visibility=" << halide_memory_visibility_name(properties.visibility) << "\n";
383 #endif
384  }
385  return block_entry;
386 }
387 
388 BlockAllocator::BlockEntry *
389 BlockAllocator::reserve_block_entry(void *user_context, const MemoryProperties &properties, size_t size, bool dedicated) {
390 #ifdef DEBUG_RUNTIME_INTERNAL
391  debug(user_context) << "BlockAllocator: reserving block ... !\n"
392  << " requested_size=" << (uint32_t)size << "\n"
393  << " requested_is_dedicated=" << (dedicated ? "true" : "false") << "\n"
394  << " requested_usage=" << halide_memory_usage_name(properties.usage) << "\n"
395  << " requested_caching=" << halide_memory_caching_name(properties.caching) << "\n"
396  << " requested_visibility=" << halide_memory_visibility_name(properties.visibility) << "\n";
397 #endif
398  BlockEntry *block_entry = find_block_entry(user_context, properties, size, dedicated);
399  if (block_entry == nullptr) {
400 #ifdef DEBUG_RUNTIME_INTERNAL
401  debug(user_context) << "BlockAllocator: creating block ... !\n"
402  << " requested_size=" << (uint32_t)size << "\n"
403  << " requested_is_dedicated=" << (dedicated ? "true" : "false") << "\n"
404  << " requested_usage=" << halide_memory_usage_name(properties.usage) << "\n"
405  << " requested_caching=" << halide_memory_caching_name(properties.caching) << "\n"
406  << " requested_visibility=" << halide_memory_visibility_name(properties.visibility) << "\n";
407 #endif
408  block_entry = create_block_entry(user_context, properties, size, dedicated);
409  }
410 
411  if (block_entry) {
412  BlockResource *block = static_cast<BlockResource *>(block_entry->value);
413  if (block->allocator == nullptr) {
414  block->allocator = create_region_allocator(user_context, block);
415  }
416  }
417  return block_entry;
418 }
419 
420 RegionAllocator *
421 BlockAllocator::create_region_allocator(void *user_context, BlockResource *block) {
422 #ifdef DEBUG_RUNTIME_INTERNAL
423  debug(user_context) << "BlockAllocator: Creating region allocator ("
424  << "user_context=" << (void *)(user_context) << " "
425  << "block_resource=" << (void *)(block) << ")...\n";
426 #endif
427  halide_abort_if_false(user_context, block != nullptr);
428  RegionAllocator *region_allocator = RegionAllocator::create(
429  user_context, block, {allocators.system, allocators.region});
430 
431  if (region_allocator == nullptr) {
432  error(user_context) << "BlockAllocator: Failed to create new region allocator!\n";
433  return nullptr;
434  }
435 
436  return region_allocator;
437 }
438 
439 int BlockAllocator::destroy_region_allocator(void *user_context, RegionAllocator *region_allocator) {
440 #ifdef DEBUG_RUNTIME_INTERNAL
441  debug(user_context) << "BlockAllocator: Destroying region allocator ("
442  << "user_context=" << (void *)(user_context) << " "
443  << "region_allocator=" << (void *)(region_allocator) << ")...\n";
444 #endif
445  if (region_allocator == nullptr) {
446  return 0;
447  }
448  return RegionAllocator::destroy(user_context, region_allocator);
449 }
450 
451 BlockAllocator::BlockEntry *
452 BlockAllocator::create_block_entry(void *user_context, const MemoryProperties &properties, size_t size, bool dedicated) {
453  if (config.maximum_pool_size && (pool_size() >= config.maximum_pool_size)) {
454  error(user_context) << "BlockAllocator: No free blocks found! Maximum pool size reached ("
455  << (int32_t)(config.maximum_pool_size) << " bytes or "
456  << (int32_t)(config.maximum_pool_size / (1024 * 1024)) << " MB)\n";
457  return nullptr;
458  }
459 
460  if (config.maximum_block_count && (block_count() >= config.maximum_block_count)) {
461  error(user_context) << "BlockAllocator: No free blocks found! Maximum block count reached ("
462  << (int32_t)(config.maximum_block_count) << ")!\n";
463  return nullptr;
464  }
465 
466  BlockEntry *block_entry = block_list.append(user_context);
467  if (block_entry == nullptr) {
468  debug(user_context) << "BlockAllocator: Failed to allocate new block entry!\n";
469  return nullptr;
470  }
471 
472 #ifdef DEBUG_RUNTIME_INTERNAL
473  debug(user_context) << "BlockAllocator: Creating block entry ("
474  << "block_entry=" << (void *)(block_entry) << " "
475  << "block=" << (void *)(block_entry->value) << " "
476  << "allocator=" << (void *)(allocators.block.allocate) << ")...\n";
477 #endif
478 
479  BlockResource *block = static_cast<BlockResource *>(block_entry->value);
480  block->memory.size = constrain_requested_size(size);
481  block->memory.handle = nullptr;
482  block->memory.properties = properties;
483  block->memory.properties.nearest_multiple = max(config.nearest_multiple, properties.nearest_multiple);
484  block->memory.dedicated = dedicated;
485  block->reserved = 0;
486  block->allocator = create_region_allocator(user_context, block);
487  alloc_memory_block(user_context, block);
488  return block_entry;
489 }
490 
491 int BlockAllocator::release_block_entry(void *user_context, BlockAllocator::BlockEntry *block_entry) {
492 #ifdef DEBUG_RUNTIME_INTERNAL
493  debug(user_context) << "BlockAllocator: Releasing block entry ("
494  << "block_entry=" << (void *)(block_entry) << " "
495  << "block=" << (void *)(block_entry->value) << ")...\n";
496 #endif
497  BlockResource *block = static_cast<BlockResource *>(block_entry->value);
498  if (block->allocator) {
499  return block->allocator->release(user_context);
500  }
501  return 0;
502 }
503 
504 int BlockAllocator::destroy_block_entry(void *user_context, BlockAllocator::BlockEntry *block_entry) {
505 #ifdef DEBUG_RUNTIME_INTERNAL
506  debug(user_context) << "BlockAllocator: Destroying block entry ("
507  << "block_entry=" << (void *)(block_entry) << " "
508  << "block=" << (void *)(block_entry->value) << " "
509  << "deallocator=" << (void *)(allocators.block.deallocate) << ")...\n";
510 #endif
511  BlockResource *block = static_cast<BlockResource *>(block_entry->value);
512  if (block->allocator) {
513  destroy_region_allocator(user_context, block->allocator);
514  block->allocator = nullptr;
515  }
516  free_memory_block(user_context, block);
517  block_list.remove(user_context, block_entry);
518  return 0;
519 }
520 
521 int BlockAllocator::alloc_memory_block(void *user_context, BlockResource *block) {
522 #ifdef DEBUG_RUNTIME_INTERNAL
523  debug(user_context) << "BlockAllocator: Allocating block (ptr=" << (void *)block << " allocator=" << (void *)allocators.block.allocate << ")...\n";
524 #endif
525  halide_abort_if_false(user_context, allocators.block.allocate != nullptr);
526  MemoryBlock *memory_block = &(block->memory);
527  allocators.block.allocate(user_context, memory_block);
528  block->reserved = 0;
529  return 0;
530 }
531 
532 int BlockAllocator::free_memory_block(void *user_context, BlockResource *block) {
533 #ifdef DEBUG_RUNTIME_INTERNAL
534  debug(user_context) << "BlockAllocator: Deallocating block (ptr=" << (void *)block << " allocator=" << (void *)allocators.block.deallocate << ")...\n";
535 #endif
536  halide_abort_if_false(user_context, allocators.block.deallocate != nullptr);
537  MemoryBlock *memory_block = &(block->memory);
538  allocators.block.deallocate(user_context, memory_block);
539  memory_block->handle = nullptr;
540  block->reserved = 0;
541  block->memory.size = 0;
542  return 0;
543 }
544 
545 size_t BlockAllocator::constrain_requested_size(size_t size) const {
546  size_t actual_size = size;
547  if (config.nearest_multiple) {
548  actual_size = (((actual_size + config.nearest_multiple - 1) / config.nearest_multiple) * config.nearest_multiple);
549  }
550  if (config.minimum_block_size) {
551  actual_size = ((actual_size < config.minimum_block_size) ?
552  config.minimum_block_size :
553  actual_size);
554  }
555  if (config.maximum_block_size) {
556  actual_size = ((actual_size > config.maximum_block_size) ?
557  config.maximum_block_size :
558  actual_size);
559  }
560 
561  return actual_size;
562 }
563 
564 bool BlockAllocator::is_compatible_block(const BlockResource *block, const MemoryProperties &properties) const {
565  if (properties.caching != MemoryCaching::DefaultCaching) {
566  if (properties.caching != block->memory.properties.caching) {
567  return false;
568  }
569  }
570 
571  if (properties.visibility != MemoryVisibility::DefaultVisibility) {
572  if (properties.visibility != block->memory.properties.visibility) {
573  return false;
574  }
575  }
576 
577  if (properties.usage != MemoryUsage::DefaultUsage) {
578  if (properties.usage != block->memory.properties.usage) {
579  return false;
580  }
581  }
582 
583  return true;
584 }
585 
587  return allocators;
588 }
589 
591  return config;
592 }
593 
595  static Config result;
596  return result;
597 }
598 
600  return block_list.size();
601 }
602 
604  size_t total_size = 0;
605  BlockEntry const *block_entry = nullptr;
606  for (block_entry = block_list.front(); block_entry != nullptr; block_entry = block_entry->next_ptr) {
607  const BlockResource *block = static_cast<BlockResource *>(block_entry->value);
608  if (block != nullptr) {
609  total_size += block->memory.size;
610  }
611  }
612  return total_size;
613 }
614 
615 // --
616 
617 } // namespace Internal
618 } // namespace Runtime
619 } // namespace Halide
620 
621 #endif // HALIDE_RUNTIME_BLOCK_ALLOCATOR_H
Halide::Runtime::Internal::BlockAllocator::MemoryAllocators::block
MemoryBlockAllocatorFns block
Definition: block_allocator.h:38
Halide::Runtime::Internal::BlockAllocator::Config::nearest_multiple
size_t nearest_multiple
Definition: block_allocator.h:49
int32_t
signed __INT32_TYPE__ int32_t
Definition: runtime_internal.h:24
Halide::Runtime::Internal::RegionAllocator::reclaim
int reclaim(void *user_context, MemoryRegion *memory_region)
Definition: region_allocator.h:194
halide_error_code_internal_error
@ halide_error_code_internal_error
There is a bug in the Halide compiler.
Definition: HalideRuntime.h:1127
Halide::Runtime::Internal::RegionAllocator::destroy
static int destroy(void *user_context, RegionAllocator *region_allocator)
Definition: region_allocator.h:126
Halide::Runtime::Internal::LinkedList::front
EntryType * front()
Definition: linked_list.h:117
Halide::Runtime::Internal::RegionAllocator::release
int release(void *user_context, MemoryRegion *memory_region)
Definition: region_allocator.h:184
Halide::Runtime::Internal::BlockAllocator::reclaim
int reclaim(void *user_context, MemoryRegion *region)
Definition: block_allocator.h:208
Halide::Runtime::Internal::BlockAllocator::current_config
const Config & current_config() const
Definition: block_allocator.h:590
Halide::Runtime::Internal::LinkedList::size
size_t size() const
Definition: linked_list.h:295
Halide::Runtime::Internal::MemoryRegionAllocatorFns
Definition: memory_resources.h:214
Halide::Runtime::Internal::BlockAllocator::create
static BlockAllocator * create(void *user_context, const Config &config, const MemoryAllocators &allocators)
Definition: block_allocator.h:123
Halide::Runtime::Internal::MemoryBlockAllocatorFns::deallocate
DeallocateBlockFn deallocate
Definition: memory_resources.h:208
Halide::Runtime::Internal::MemoryRequest::dedicated
bool dedicated
Definition: memory_resources.h:94
Halide::Runtime::Internal::BlockAllocator::Config
Definition: block_allocator.h:43
Halide::Runtime::Internal::BlockAllocator::Config::minimum_block_size
size_t minimum_block_size
Definition: block_allocator.h:46
Halide::Runtime::Internal::BlockAllocator::MemoryAllocators::region
MemoryRegionAllocatorFns region
Definition: block_allocator.h:39
Halide::Runtime::Internal::BlockAllocator::block_count
size_t block_count() const
Definition: block_allocator.h:599
Halide::Runtime::Internal::MemoryRequest::size
size_t size
Definition: memory_resources.h:92
Halide::Runtime::Internal::MemoryVisibility::DefaultVisibility
@ DefaultVisibility
Halide::Runtime::Internal::MemoryRegion
Definition: memory_resources.h:79
halide_memory_caching_name
const WEAK char * halide_memory_caching_name(MemoryCaching value)
Definition: memory_resources.h:289
Halide::Runtime::Internal::LinkedList::EntryType::value
void * value
Definition: linked_list.h:24
Halide::Runtime::Internal::BlockAllocator::BlockAllocator
BlockAllocator()=delete
Halide::Runtime::Internal::LinkedList::append
EntryType * append(void *user_context)
Definition: linked_list.h:150
Halide::Runtime::Internal::MemoryUsage::DefaultUsage
@ DefaultUsage
Halide::Runtime::Internal::BlockAllocator::reserve
MemoryRegion * reserve(void *user_context, const MemoryRequest &request)
Definition: block_allocator.h:154
Halide::Runtime::Internal::BlockAllocator
Allocator class interface for managing large contiguous blocks of memory, which are then sub-allocate...
Definition: block_allocator.h:25
Halide::Runtime::Internal::LinkedList::EntryType::next_ptr
EntryType * next_ptr
Definition: linked_list.h:26
Halide::Runtime::Internal::MemoryRequest::properties
MemoryProperties properties
Definition: memory_resources.h:95
uint64_t
unsigned __INT64_TYPE__ uint64_t
Definition: runtime_internal.h:23
Halide::Runtime::Internal::SystemMemoryAllocatorFns::allocate
AllocateSystemFn allocate
Definition: memory_resources.h:194
Halide
This file defines the class FunctionDAG, which is our representation of a Halide pipeline,...
Definition: AbstractGenerator.h:19
Halide::Runtime::Internal::BlockAllocator::pool_size
size_t pool_size() const
Definition: block_allocator.h:603
Halide::Runtime::Internal::LinkedList::remove
void remove(void *user_context, EntryType *entry_ptr)
Definition: linked_list.h:217
Halide::Runtime::Internal::BlockAllocator::destroy
static void destroy(void *user_context, BlockAllocator *block_allocator)
Definition: block_allocator.h:137
Halide::LinkageType::Internal
@ Internal
Not visible externally, similar to 'static' linkage in C.
Halide::Runtime::Internal::BlockAllocator::collect
bool collect(void *user_context)
Definition: block_allocator.h:230
Halide::Runtime::Internal::BlockAllocator::operator=
BlockAllocator & operator=(const BlockAllocator &)=delete
Halide::Runtime::Internal::LinkedList::back
EntryType * back()
Definition: linked_list.h:121
Halide::Runtime::Internal::BlockAllocator::MemoryAllocators::system
SystemMemoryAllocatorFns system
Definition: block_allocator.h:37
Halide::Runtime::Internal::MemoryCaching::DefaultCaching
@ DefaultCaching
Halide::Runtime::Internal::SystemMemoryAllocatorFns::deallocate
DeallocateSystemFn deallocate
Definition: memory_resources.h:195
Halide::Runtime::Internal::MemoryRequest::offset
size_t offset
Definition: memory_resources.h:91
Halide::Runtime::Internal::BlockAllocator::release
int release(void *user_context, MemoryRegion *region)
Definition: block_allocator.h:197
region_allocator.h
Halide::Runtime::Internal::BlockAllocator::Config::maximum_block_count
size_t maximum_block_count
Definition: block_allocator.h:48
halide_memory_visibility_name
const WEAK char * halide_memory_visibility_name(MemoryVisibility value)
Definition: memory_resources.h:229
memory_resources.h
Halide::Runtime::Internal::BlockAllocator::Config::maximum_pool_size
size_t maximum_pool_size
Definition: block_allocator.h:45
Halide::Runtime::Internal::MemoryProperties
Definition: memory_resources.h:56
Halide::Runtime::Internal::BlockAllocator::current_allocators
const MemoryAllocators & current_allocators() const
Definition: block_allocator.h:586
Halide::Runtime::Internal::MemoryBlockAllocatorFns::allocate
AllocateBlockFn allocate
Definition: memory_resources.h:207
Halide::Runtime::Internal::LinkedList::initialize
void initialize(void *user_context, uint32_t entry_size, uint32_t capacity=default_capacity, const SystemMemoryAllocatorFns &allocator=default_allocator())
Definition: linked_list.h:92
Halide::Runtime::Internal::BlockResource::memory
MemoryBlock memory
Definition: memory_resources.h:104
Halide::Runtime::Internal::LinkedList
Definition: linked_list.h:13
Halide::Runtime::Internal::MemoryBlock::size
size_t size
Definition: memory_resources.h:67
Halide::Runtime::Internal::BlockAllocator::MemoryAllocators
Definition: block_allocator.h:36
Halide::Runtime::Internal::BlockResource::allocator
RegionAllocator * allocator
Definition: memory_resources.h:105
Halide::Runtime::Internal::RegionAllocator
Allocator class interface for sub-allocating a contiguous memory block into smaller regions of memory...
Definition: region_allocator.h:24
halide_memory_usage_name
const WEAK char * halide_memory_usage_name(MemoryUsage value)
Definition: memory_resources.h:256
Halide::Runtime::Internal::MemoryProperties::caching
MemoryCaching caching
Definition: memory_resources.h:59
Halide::Runtime::Internal::BlockAllocator::Config::maximum_block_size
size_t maximum_block_size
Definition: block_allocator.h:47
Halide::Runtime::Internal::BlockResource
Definition: memory_resources.h:103
Halide::Runtime::Internal::MemoryProperties::visibility
MemoryVisibility visibility
Definition: memory_resources.h:57
Halide::Runtime::Internal::RegionAllocator::create
static RegionAllocator * create(void *user_context, BlockResource *block, const MemoryAllocators &ma)
Definition: region_allocator.h:113
Halide::Runtime::Internal::LinkedList::EntryType
Definition: linked_list.h:23
Halide::Runtime::Internal::MemoryProperties::usage
MemoryUsage usage
Definition: memory_resources.h:58
Halide::Runtime::Internal::SystemMemoryAllocatorFns
Definition: memory_resources.h:193
linked_list.h
Halide::Runtime::Internal::RegionAllocator::collect
bool collect(void *user_context)
Definition: region_allocator.h:635
Halide::Runtime::Internal::LinkedList::EntryType::prev_ptr
EntryType * prev_ptr
Definition: linked_list.h:25
halide_abort_if_false
#define halide_abort_if_false(user_context, cond)
Definition: runtime_internal.h:262
Halide::Runtime::Internal::BlockAllocator::Config::initial_capacity
size_t initial_capacity
Definition: block_allocator.h:44
Halide::Runtime::Internal::BlockAllocator::~BlockAllocator
~BlockAllocator()=delete
Halide::Runtime::Internal::MemoryRequest
Definition: memory_resources.h:90
uint32_t
unsigned __INT32_TYPE__ uint32_t
Definition: runtime_internal.h:25
Halide::Runtime::Internal::BlockAllocator::default_config
const Config & default_config() const
Definition: block_allocator.h:594
Halide::Runtime::Internal::LinkedList::destroy
void destroy(void *user_context)
Definition: linked_list.h:102
Halide::max
Expr max(const FuncRef &a, const FuncRef &b)
Definition: Func.h:587
Halide::Runtime::Internal::RegionAllocator::find_allocator
static RegionAllocator * find_allocator(void *user_context, MemoryRegion *memory_region)
Definition: region_allocator.h:217
Halide::Runtime::Internal::RegionAllocator::reserve
MemoryRegion * reserve(void *user_context, const MemoryRequest &request)
Definition: region_allocator.h:149
Halide::Runtime::Internal::MemoryBlockAllocatorFns
Definition: memory_resources.h:206
Halide::Runtime::Internal::BlockResource::reserved
size_t reserved
Definition: memory_resources.h:107
Halide::Runtime::Internal::MemoryRegion::size
size_t size
Definition: memory_resources.h:82
Halide::Runtime::Internal::BlockAllocator::retain
int retain(void *user_context, MemoryRegion *region)
Definition: block_allocator.h:219
Halide::Runtime::Internal::RegionAllocator::retain
int retain(void *user_context, MemoryRegion *memory_region)
Definition: region_allocator.h:209