Halide 16.0.0
Halide compiler and libraries
Loading...
Searching...
No Matches
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
10namespace Halide {
11namespace Runtime {
12namespace 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 */
26public:
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
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
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
72private:
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
123BlockAllocator *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
137void 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
145void 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
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
198 if (memory_region == nullptr) {
200 }
202 if (allocator == nullptr) {
204 }
205 return allocator->release(user_context, memory_region);
206}
207
209 if (memory_region == nullptr) {
211 }
213 if (allocator == nullptr) {
215 }
216 return allocator->reclaim(user_context, memory_region);
217}
218
220 if (memory_region == nullptr) {
222 }
224 if (allocator == nullptr) {
226 }
227 return allocator->retain(user_context, memory_region);
228}
229
230bool 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) {
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
261 }
262 return result;
263}
264
265int 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);
271 }
272 return 0;
273}
274
275int 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);
281 }
282 block_list.destroy(user_context);
283 return 0;
284}
285
286MemoryRegion *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
302bool 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
350BlockAllocator::BlockEntry *
351BlockAllocator::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 }
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
388BlockAllocator::BlockEntry *
389BlockAllocator::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
420RegionAllocator *
421BlockAllocator::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
439int 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
451BlockAllocator::BlockEntry *
452BlockAllocator::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
491int 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
504int 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
521int 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
532int 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
545size_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) {
552 config.minimum_block_size :
554 }
555 if (config.maximum_block_size) {
557 config.maximum_block_size :
559 }
560
561 return actual_size;
562}
563
564bool 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_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
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)
BlockAllocator & operator=(const BlockAllocator &)=delete
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)
void remove(void *user_context, EntryType *entry_ptr)
void destroy(void *user_context)
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_caching_name(MemoryCaching value)
WEAK const char * halide_memory_usage_name(MemoryUsage value)
WEAK const char * halide_memory_visibility_name(MemoryVisibility 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 cast(Expr a)
Cast an expression to the halide type corresponding to the C++ type T.
Definition IROperator.h:358
Expr max(const FuncRef &a, const FuncRef &b)
Definition Func.h:587
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