Halide 19.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 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
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
73private:
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
124BlockAllocator *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
138void 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
146void 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
155MemoryRegion *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
200int 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
211int 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
222int 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
233bool 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
268int 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
278int 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
289MemoryRegion *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
305bool 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
353BlockAllocator::BlockEntry *
354BlockAllocator::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
391BlockAllocator::BlockEntry *
392BlockAllocator::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
423RegionAllocator *
424BlockAllocator::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
442int 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
454BlockAllocator::BlockEntry *
455BlockAllocator::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
498int 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
511int 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
528int 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
539int 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
552size_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
571int 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
598bool 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
This file declares the routines used by Halide internally in its runtime.
@ 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)
int conform(void *user_context, MemoryRequest *request) const
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 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