Halide 22.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
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 */
25 class BlockAllocator {
26public:
27 // disable copy constructors and assignment for
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
36 struct MemoryAllocators {
37 SystemMemoryAllocatorFns system;
38 MemoryBlockAllocatorFns block;
39 MemoryRegionAllocatorFns region;
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
73private:
74 // Linked-list for storing the block resources
75 typedef LinkedList::EntryType BlockEntry;
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 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
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) {
202 return halide_error_code_internal_error;
203 }
204 RegionAllocator *allocator = RegionAllocator::find_allocator(user_context, memory_region);
205 if (allocator == nullptr) {
206 return halide_error_code_internal_error;
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) {
213 return halide_error_code_internal_error;
214 }
215 RegionAllocator *allocator = RegionAllocator::find_allocator(user_context, memory_region);
216 if (allocator == nullptr) {
217 return halide_error_code_internal_error;
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) {
224 return halide_error_code_internal_error;
225 }
226 RegionAllocator *allocator = RegionAllocator::find_allocator(user_context, memory_region);
227 if (allocator == nullptr) {
228 return halide_error_code_internal_error;
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
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#ifdef DEBUG_RUNTIME_INTERNAL
472 debug(user_context) << "BlockAllocator: Failed to allocate new block entry\n";
473#endif
474 return nullptr;
475 }
476
477#ifdef DEBUG_RUNTIME_INTERNAL
478 debug(user_context) << "BlockAllocator: Creating block entry ("
479 << "block_entry=" << (void *)(block_entry) << " "
480 << "block=" << (void *)(block_entry->value) << " "
481 << "allocator=" << (void *)(allocators.block.allocate) << ")...";
482#endif
483
484 // Constrain the request to the a valid block allocation
485 MemoryRequest block_request = request;
486 conform(user_context, &block_request);
487
488 // Create the block resource itself
489 BlockResource *block = static_cast<BlockResource *>(block_entry->value);
490 block->memory.size = block_request.size;
491 block->memory.handle = nullptr;
492 block->memory.properties = block_request.properties;
493 block->memory.dedicated = block_request.dedicated;
494 block->reserved = 0;
495 block->allocator = create_region_allocator(user_context, block);
496 int error_code = alloc_memory_block(user_context, block);
497 if (error_code != 0) {
498#ifdef DEBUG_RUNTIME_INTERNAL
499 debug(user_context) << "BlockAllocator: Failed to allocate memory block\n";
500#endif
501 destroy_block_entry(user_context, block_entry);
502 return nullptr;
503 }
504 return block_entry;
505}
506
507int BlockAllocator::release_block_entry(void *user_context, BlockAllocator::BlockEntry *block_entry) {
508#ifdef DEBUG_RUNTIME_INTERNAL
509 debug(user_context) << "BlockAllocator: Releasing block entry ("
510 << "block_entry=" << (void *)(block_entry) << " "
511 << "block=" << (void *)(block_entry->value) << ")...";
512#endif
513 BlockResource *block = static_cast<BlockResource *>(block_entry->value);
514 if (block->allocator) {
515 return block->allocator->release(user_context);
516 }
517 return 0;
518}
519
520int BlockAllocator::destroy_block_entry(void *user_context, BlockAllocator::BlockEntry *block_entry) {
521#ifdef DEBUG_RUNTIME_INTERNAL
522 debug(user_context) << "BlockAllocator: Destroying block entry ("
523 << "block_entry=" << (void *)(block_entry) << " "
524 << "block=" << (void *)(block_entry->value) << " "
525 << "deallocator=" << (void *)(allocators.block.deallocate) << ")...";
526#endif
527 BlockResource *block = static_cast<BlockResource *>(block_entry->value);
528 if (block->allocator) {
529 destroy_region_allocator(user_context, block->allocator);
530 block->allocator = nullptr;
531 }
532 int error_code = free_memory_block(user_context, block);
533 block_list.remove(user_context, block_entry);
534 return error_code;
535}
536
537int BlockAllocator::alloc_memory_block(void *user_context, BlockResource *block) {
538#ifdef DEBUG_RUNTIME_INTERNAL
539 debug(user_context) << "BlockAllocator: Allocating block (ptr=" << (void *)block << " allocator=" << (void *)allocators.block.allocate << ")...";
540#endif
541 halide_abort_if_false(user_context, allocators.block.allocate != nullptr);
542 MemoryBlock *memory_block = &(block->memory);
543 int error_code = allocators.block.allocate(user_context, memory_block);
544 block->reserved = 0;
545 return error_code;
546}
547
548int BlockAllocator::free_memory_block(void *user_context, BlockResource *block) {
549#ifdef DEBUG_RUNTIME_INTERNAL
550 debug(user_context) << "BlockAllocator: Deallocating block (ptr=" << (void *)block << " allocator=" << (void *)allocators.block.deallocate << ")...";
551#endif
552 halide_abort_if_false(user_context, allocators.block.deallocate != nullptr);
553 MemoryBlock *memory_block = &(block->memory);
554 int error_code = allocators.block.deallocate(user_context, memory_block);
555 memory_block->handle = nullptr;
556 block->reserved = 0;
557 block->memory.size = 0;
558 return error_code;
559}
560
561size_t BlockAllocator::constrain_requested_size(size_t size) const {
562 size_t actual_size = size;
563 if (config.nearest_multiple) {
564 actual_size = (((actual_size + config.nearest_multiple - 1) / config.nearest_multiple) * config.nearest_multiple);
565 }
566 if (config.minimum_block_size) {
567 actual_size = ((actual_size < config.minimum_block_size) ?
568 config.minimum_block_size :
569 actual_size);
570 }
571 if (config.maximum_block_size) {
572 actual_size = ((actual_size > config.maximum_block_size) ?
573 config.maximum_block_size :
574 actual_size);
575 }
576
577 return actual_size;
578}
579
580 int BlockAllocator::conform(void *user_context, MemoryRequest *request) const {
581
582 request->properties.nearest_multiple = max(config.nearest_multiple, request->properties.nearest_multiple);
583
584 if (request->properties.nearest_multiple) {
585 size_t nm = request->properties.nearest_multiple;
586 request->size = (((request->size + nm - 1) / nm) * nm); // round up to nearest multiple
587 }
588
589 if (config.minimum_block_size) {
590 request->size = ((request->size < config.minimum_block_size) ?
591 config.minimum_block_size :
592 request->size);
593 }
594 if (config.maximum_block_size) {
595 request->size = ((request->size > config.maximum_block_size) ?
596 config.maximum_block_size :
597 request->size);
598 }
599
600 if (allocators.block.conform) {
601 return allocators.block.conform(user_context, request);
602 }
603
604 return 0;
605}
606
607bool BlockAllocator::is_compatible_block(const BlockResource *block, const MemoryProperties &properties) const {
608 if (properties.caching != MemoryCaching::DefaultCaching) {
609 if (properties.caching != block->memory.properties.caching) {
610 return false;
611 }
612 }
613
614 if (properties.visibility != MemoryVisibility::DefaultVisibility) {
615 if (properties.visibility != block->memory.properties.visibility) {
616 return false;
617 }
618 }
619
620 if (properties.usage != MemoryUsage::DefaultUsage) {
621 if (properties.usage != block->memory.properties.usage) {
622 return false;
623 }
624 }
625
626 return true;
627}
628
629 const BlockAllocator::MemoryAllocators &BlockAllocator::current_allocators() const {
630 return allocators;
631}
632
633 const BlockAllocator::Config &BlockAllocator::current_config() const {
634 return config;
635}
636
637 const BlockAllocator::Config &BlockAllocator::default_config() const {
638 static Config result;
639 return result;
640}
641
642 size_t BlockAllocator::block_count() const {
643 return block_list.size();
644}
645
646 size_t BlockAllocator::pool_size() const {
647 size_t total_size = 0;
648 BlockEntry const *block_entry = nullptr;
649 for (block_entry = block_list.front(); block_entry != nullptr; block_entry = block_entry->next_ptr) {
650 const BlockResource *block = static_cast<BlockResource *>(block_entry->value);
651 if (block != nullptr) {
652 total_size += block->memory.size;
653 }
654 }
655 return total_size;
656}
657
658// --
659
660} // namespace Internal
661} // namespace Runtime
662} // namespace Halide
663
664#endif // HALIDE_RUNTIME_BLOCK_ALLOCATOR_H
debug
#define debug(n)
For optional debugging during codegen, use the debug macro as follows:
Definition: Debug.h:52
halide_error_code_internal_error
@ halide_error_code_internal_error
There is a bug in the Halide compiler.
Definition: HalideRuntime.h:1164
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::BlockAllocator::BlockAllocator
BlockAllocator(const BlockAllocator &)=delete
Halide::Runtime::Internal::BlockAllocator::default_config
const Config & default_config() const
Definition: block_allocator.h:637
Halide::Runtime::Internal::BlockAllocator::collect
bool collect(void *user_context)
Definition: block_allocator.h:233
Halide::Runtime::Internal::BlockAllocator::block_count
size_t block_count() const
Definition: block_allocator.h:642
Halide::Runtime::Internal::BlockAllocator::BlockAllocator
BlockAllocator()=delete
Halide::Runtime::Internal::BlockAllocator::reserve
MemoryRegion * reserve(void *user_context, const MemoryRequest &request)
Definition: block_allocator.h:155
Halide::Runtime::Internal::BlockAllocator::release
int release(void *user_context, MemoryRegion *region)
Definition: block_allocator.h:200
Halide::Runtime::Internal::BlockAllocator::pool_size
size_t pool_size() const
Definition: block_allocator.h:646
Halide::Runtime::Internal::BlockAllocator::current_config
const Config & current_config() const
Definition: block_allocator.h:633
Halide::Runtime::Internal::BlockAllocator::retain
int retain(void *user_context, MemoryRegion *region)
Definition: block_allocator.h:222
Halide::Runtime::Internal::BlockAllocator::~BlockAllocator
~BlockAllocator()=delete
Halide::Runtime::Internal::BlockAllocator::destroy
static void destroy(void *user_context, BlockAllocator *block_allocator)
Definition: block_allocator.h:138
Halide::Runtime::Internal::BlockAllocator::create
static BlockAllocator * create(void *user_context, const Config &config, const MemoryAllocators &allocators)
Definition: block_allocator.h:124
Halide::Runtime::Internal::BlockAllocator::reclaim
int reclaim(void *user_context, MemoryRegion *region)
Definition: block_allocator.h:211
Halide::Runtime::Internal::BlockAllocator::conform
int conform(void *user_context, MemoryRequest *request) const
Definition: block_allocator.h:580
Halide::Runtime::Internal::BlockAllocator::operator=
BlockAllocator & operator=(const BlockAllocator &)=delete
Halide::Runtime::Internal::BlockAllocator::current_allocators
const MemoryAllocators & current_allocators() const
Definition: block_allocator.h:629
Halide::Runtime::Internal::LinkedList
Definition: linked_list.h:13
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::LinkedList::back
EntryType * back()
Definition: linked_list.h:121
Halide::Runtime::Internal::LinkedList::append
EntryType * append(void *user_context)
Definition: linked_list.h:150
Halide::Runtime::Internal::LinkedList::remove
void remove(void *user_context, EntryType *entry_ptr)
Definition: linked_list.h:217
Halide::Runtime::Internal::LinkedList::size
size_t size() const
Definition: linked_list.h:295
Halide::Runtime::Internal::LinkedList::destroy
void destroy(void *user_context)
Definition: linked_list.h:102
Halide::Runtime::Internal::LinkedList::front
EntryType * front()
Definition: linked_list.h:117
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::Runtime::Internal::RegionAllocator::destroy
static int destroy(void *user_context, RegionAllocator *region_allocator)
Definition: region_allocator.h:127
Halide::Runtime::Internal::RegionAllocator::find_allocator
static RegionAllocator * find_allocator(void *user_context, MemoryRegion *memory_region)
Definition: region_allocator.h:240
Halide::Runtime::Internal::RegionAllocator::collect
bool collect(void *user_context)
Definition: region_allocator.h:692
Halide::Runtime::Internal::RegionAllocator::create
static RegionAllocator * create(void *user_context, BlockResource *block, const MemoryAllocators &ma)
Definition: region_allocator.h:114
linked_list.h
memory_resources.h
halide_memory_caching_name
WEAK const char * halide_memory_caching_name(MemoryCaching value)
Definition: memory_resources.h:293
halide_memory_usage_name
WEAK const char * halide_memory_usage_name(MemoryUsage value)
Definition: memory_resources.h:260
halide_memory_visibility_name
WEAK const char * halide_memory_visibility_name(MemoryVisibility value)
Definition: memory_resources.h:233
Halide::Runtime::Internal::MemoryUsage::DefaultUsage
@ DefaultUsage
Halide::Runtime::Internal::MemoryVisibility::DefaultVisibility
@ DefaultVisibility
Halide::Runtime::Internal::MemoryCaching::DefaultCaching
@ DefaultCaching
Halide
This file defines the class FunctionDAG, which is our representation of a Halide pipeline,...
Definition: AbstractGenerator.h:19
Halide::LinkageType::Internal
@ Internal
Not visible externally, similar to 'static' linkage in C.
Halide::max
Expr max(const FuncRef &a, const FuncRef &b)
Definition: Func.h:628
region_allocator.h
uint64_t
unsigned __INT64_TYPE__ uint64_t
Definition: runtime_internal.h:23
int32_t
signed __INT32_TYPE__ int32_t
Definition: runtime_internal.h:24
uint32_t
unsigned __INT32_TYPE__ uint32_t
Definition: runtime_internal.h:25
halide_abort_if_false
#define halide_abort_if_false(user_context, cond)
Definition: runtime_internal.h:271
Halide::Runtime::Internal::BlockAllocator::Config
Definition: block_allocator.h:43
Halide::Runtime::Internal::BlockAllocator::Config::initial_capacity
size_t initial_capacity
Definition: block_allocator.h:44
Halide::Runtime::Internal::BlockAllocator::Config::maximum_block_count
size_t maximum_block_count
Definition: block_allocator.h:48
Halide::Runtime::Internal::BlockAllocator::Config::nearest_multiple
size_t nearest_multiple
Definition: block_allocator.h:49
Halide::Runtime::Internal::BlockAllocator::Config::minimum_block_size
size_t minimum_block_size
Definition: block_allocator.h:46
Halide::Runtime::Internal::BlockAllocator::Config::maximum_pool_size
size_t maximum_pool_size
Definition: block_allocator.h:45
Halide::Runtime::Internal::BlockAllocator::Config::maximum_block_size
size_t maximum_block_size
Definition: block_allocator.h:47
Halide::Runtime::Internal::BlockAllocator::MemoryAllocators
Definition: block_allocator.h:36
Halide::Runtime::Internal::BlockAllocator::MemoryAllocators::region
MemoryRegionAllocatorFns region
Definition: block_allocator.h:39
Halide::Runtime::Internal::BlockAllocator::MemoryAllocators::block
MemoryBlockAllocatorFns block
Definition: block_allocator.h:38
Halide::Runtime::Internal::BlockAllocator::MemoryAllocators::system
SystemMemoryAllocatorFns system
Definition: block_allocator.h:37
Halide::Runtime::Internal::BlockResource
Definition: memory_resources.h:103
Halide::Runtime::Internal::BlockResource::reserved
size_t reserved
Definition: memory_resources.h:107
Halide::Runtime::Internal::BlockResource::allocator
RegionAllocator * allocator
Definition: memory_resources.h:105
Halide::Runtime::Internal::BlockResource::memory
MemoryBlock memory
Definition: memory_resources.h:104
Halide::Runtime::Internal::LinkedList::EntryType
Definition: linked_list.h:23
Halide::Runtime::Internal::LinkedList::EntryType::prev_ptr
EntryType * prev_ptr
Definition: linked_list.h:25
Halide::Runtime::Internal::LinkedList::EntryType::next_ptr
EntryType * next_ptr
Definition: linked_list.h:26
Halide::Runtime::Internal::LinkedList::EntryType::value
void * value
Definition: linked_list.h:24
Halide::Runtime::Internal::MemoryBlockAllocatorFns
Definition: memory_resources.h:207
Halide::Runtime::Internal::MemoryBlockAllocatorFns::deallocate
DeallocateBlockFn deallocate
Definition: memory_resources.h:209
Halide::Runtime::Internal::MemoryBlockAllocatorFns::allocate
AllocateBlockFn allocate
Definition: memory_resources.h:208
Halide::Runtime::Internal::MemoryBlockAllocatorFns::conform
ConformBlockRequestFn conform
Definition: memory_resources.h:210
Halide::Runtime::Internal::MemoryBlock::properties
MemoryProperties properties
Definition: memory_resources.h:69
Halide::Runtime::Internal::MemoryBlock::size
size_t size
Definition: memory_resources.h:67
Halide::Runtime::Internal::MemoryProperties
Definition: memory_resources.h:56
Halide::Runtime::Internal::MemoryProperties::caching
MemoryCaching caching
Definition: memory_resources.h:59
Halide::Runtime::Internal::MemoryProperties::nearest_multiple
size_t nearest_multiple
Definition: memory_resources.h:61
Halide::Runtime::Internal::MemoryProperties::visibility
MemoryVisibility visibility
Definition: memory_resources.h:57
Halide::Runtime::Internal::MemoryProperties::usage
MemoryUsage usage
Definition: memory_resources.h:58
Halide::Runtime::Internal::MemoryRegionAllocatorFns
Definition: memory_resources.h:217
Halide::Runtime::Internal::MemoryRegion
Definition: memory_resources.h:79
Halide::Runtime::Internal::MemoryRequest
Definition: memory_resources.h:90
Halide::Runtime::Internal::MemoryRequest::size
size_t size
Definition: memory_resources.h:92
Halide::Runtime::Internal::MemoryRequest::offset
size_t offset
Definition: memory_resources.h:91
Halide::Runtime::Internal::MemoryRequest::dedicated
bool dedicated
Definition: memory_resources.h:94
Halide::Runtime::Internal::MemoryRequest::properties
MemoryProperties properties
Definition: memory_resources.h:95
Halide::Runtime::Internal::SystemMemoryAllocatorFns
Definition: memory_resources.h:193
Halide::Runtime::Internal::SystemMemoryAllocatorFns::deallocate
DeallocateSystemFn deallocate
Definition: memory_resources.h:195
Halide::Runtime::Internal::SystemMemoryAllocatorFns::allocate
AllocateSystemFn allocate
Definition: memory_resources.h:194
error_code
int error_code
Definition: vulkan_resources.h:182
user_context
void * user_context
Definition: vulkan_resources.h:178
allocator
VulkanMemoryAllocator * allocator
Definition: vulkan_resources.h:179