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