1#ifndef HALIDE_RUNTIME_REGION_ALLOCATOR_H
2#define HALIDE_RUNTIME_REGION_ALLOCATOR_H
119 if (result ==
nullptr) {
141 MemoryRequest block_request = {};
143 block_request.offset = 0;
160 request->
offset = actual_offset;
161 request->
size = actual_size;
173#ifdef DEBUG_RUNTIME_INTERNAL
174 debug(
user_context) <<
"RegionAllocator: Failed to conform region request! Unable to reserve memory ...\n";
180 if (remaining < region_request.
size) {
181#ifdef DEBUG_RUNTIME_INTERNAL
182 debug(
user_context) <<
"RegionAllocator: Unable to reserve more memory from block "
183 <<
"-- requested size (" << (
int32_t)(region_request.
size) <<
" bytes) "
184 <<
"greater than available (" << (
int32_t)(remaining) <<
" bytes)";
190 if (block_region ==
nullptr) {
191#ifdef DEBUG_RUNTIME_INTERNAL
192 debug(
user_context) <<
"RegionAllocator: Failed to locate region for requested size ("
198 if (can_split(block_region, region_request)) {
199#ifdef DEBUG_RUNTIME_INTERNAL
201 <<
"to accomodate requested size (" << (
int32_t)(region_request.
size) <<
" bytes)";
203 split_block_region(
user_context, block_region, region_request);
217 return release_block_region(
user_context, block_region);
242 if (block_region ==
nullptr) {
245 if (block_region->
block_ptr ==
nullptr) {
252 return ((region ==
nullptr) || (region == region->
next_ptr) || (region->
next_ptr ==
nullptr));
255bool RegionAllocator::is_block_region_suitable_for_request(
void *
user_context,
const BlockRegion *region,
const MemoryRequest &request)
const {
256 if (!is_available(region)) {
257#ifdef DEBUG_RUNTIME_INTERNAL
258 debug(
user_context) <<
" skipping block region ... not available! ("
259 <<
" block_region=" << (
void *)region
260 <<
" region_size=" << (
uint32_t)(region->memory.size)
266 MemoryRequest region_request = request;
269#ifdef DEBUG_RUNTIME_INTERNAL
270 debug(
user_context) <<
"RegionAllocator: Failed to conform region request! Unable to reserve memory ...\n";
276 if (!is_compatible_block_region(region, region_request.properties)) {
277#ifdef DEBUG_RUNTIME_INTERNAL
278 debug(
user_context) <<
" skipping block region ... incompatible properties! ("
279 <<
" block_region=" << (
void *)region
280 <<
" region_size=" << (
uint32_t)(region->memory.size)
287 if (region_request.size > region->memory.size) {
288#ifdef DEBUG_RUNTIME_INTERNAL
289 debug(
user_context) <<
" skipping block region ... not enough space for adjusted size! ("
290 <<
" block_region=" << (
void *)region
291 <<
" request_size=" << (
uint32_t)(request.size)
292 <<
" actual_size=" << (
uint32_t)(region_request.size)
293 <<
" region_size=" << (
uint32_t)(region->memory.size)
301#ifdef DEBUG_RUNTIME_INTERNAL
302 debug(
user_context) <<
" found suitable block region! ("
303 <<
" block_region=" << (
void *)region
304 <<
" request_size=" << (
uint32_t)(request.size)
305 <<
" actual_size=" << (
uint32_t)(region_request.size)
306 <<
" region_size=" << (
uint32_t)(region->memory.size)
315BlockRegion *RegionAllocator::find_block_region(
void *
user_context,
const MemoryRequest &request) {
316#ifdef DEBUG_RUNTIME_INTERNAL
317 debug(
user_context) <<
"RegionAllocator: find block region ( "
319 <<
"requested_size=" << (
uint32_t)request.size <<
" "
320 <<
"requested_is_dedicated=" << (request.dedicated ?
"true" :
"false") <<
" "
325 BlockRegion *block_region = block->
regions;
326 while (block_region !=
nullptr) {
327 if (is_block_region_suitable_for_request(
user_context, block_region, request)) {
328#ifdef DEBUG_RUNTIME_INTERNAL
329 debug(
user_context) <<
"RegionAllocator: found suitable region ( "
331 <<
"block_resource=" << (
void *)block <<
" "
334 <<
"requested_size=" << (
uint32_t)request.size <<
" "
335 <<
"requested_is_dedicated=" << (request.dedicated ?
"true" :
"false") <<
" "
344 block_region =
nullptr;
347 block_region = block_region->next_ptr;
350 if (block_region ==
nullptr) {
351#ifdef DEBUG_RUNTIME_INTERNAL
352 debug(
user_context) <<
"RegionAllocator: couldn't find suitable region! ("
354 <<
"requested_size=" << (
uint32_t)request.size <<
" "
355 <<
"requested_is_dedicated=" << (request.dedicated ?
"true" :
"false") <<
" "
365bool RegionAllocator::is_available(
const BlockRegion *block_region)
const {
366 if (block_region ==
nullptr) {
369 if (block_region->usage_count > 0) {
378bool RegionAllocator::can_coalesce(
const BlockRegion *block_region)
const {
379 if (!is_available(block_region)) {
382 if (is_available(block_region->prev_ptr)) {
385 if (is_available(block_region->next_ptr)) {
391BlockRegion *RegionAllocator::coalesce_block_regions(
void *
user_context, BlockRegion *block_region) {
393 if ((block_region->usage_count == 0) && (block_region->memory.handle !=
nullptr)) {
394#ifdef DEBUG_RUNTIME_INTERNAL
395 debug(
user_context) <<
"RegionAllocator: Freeing unused region to coalesce ("
396 <<
"block_ptr=" << (
void *)block_region->block_ptr <<
" "
397 <<
"block_region=" << (
void *)block_region <<
" "
398 <<
"memory_size=" << (
uint32_t)(block_region->memory.size) <<
" "
403 MemoryRegion *memory_region = &(block_region->memory);
405 block_region->memory.handle =
nullptr;
408 BlockRegion *prev_region = block_region->
prev_ptr;
409 if (is_available(prev_region) && (prev_region != block_region)) {
411#ifdef DEBUG_RUNTIME_INTERNAL
413 <<
"previous region (offset=" << (
int32_t)prev_region->memory.offset <<
" size=" << (
int32_t)(prev_region->memory.size) <<
" bytes) "
414 <<
"into current region (offset=" << (
int32_t)block_region->memory.offset <<
" size=" << (
int32_t)(block_region->memory.size) <<
" bytes)!";
417 prev_region->next_ptr = block_region->next_ptr;
418 if (block_region->next_ptr) {
419 block_region->next_ptr->prev_ptr = prev_region;
421 prev_region->memory.size += block_region->memory.size;
423 block_region = prev_region;
426 BlockRegion *next_region = block_region->
next_ptr;
427 if (is_available(next_region) && (next_region != block_region)) {
429#ifdef DEBUG_RUNTIME_INTERNAL
431 <<
"next region (offset=" << (
int32_t)next_region->memory.offset <<
" size=" << (
int32_t)(next_region->memory.size) <<
" bytes) "
432 <<
"into current region (offset=" << (
int32_t)block_region->memory.offset <<
" size=" << (
int32_t)(block_region->memory.size) <<
" bytes)";
435 if (next_region->next_ptr) {
436 next_region->next_ptr->prev_ptr = block_region;
438 block_region->next_ptr = next_region->next_ptr;
439 block_region->memory.size += next_region->memory.size;
446bool RegionAllocator::can_split(
const BlockRegion *block_region,
const MemoryRequest &split_request)
const {
447 return (block_region && (block_region->memory.size > split_request.size) && (block_region->usage_count == 0));
450BlockRegion *RegionAllocator::split_block_region(
void *
user_context, BlockRegion *block_region,
const MemoryRequest &request) {
452 if ((block_region->usage_count == 0) && (block_region->memory.handle !=
nullptr)) {
453#ifdef DEBUG_RUNTIME_INTERNAL
454 debug(
user_context) <<
"RegionAllocator: Split deallocate region ("
455 <<
"block_ptr=" << (
void *)block_region->block_ptr <<
" "
456 <<
"block_region=" << (
void *)block_region <<
" "
457 <<
"memory_size=" << (
uint32_t)(block_region->memory.size) <<
" "
458 <<
"block_reserved=" << (
uint32_t)block_region->block_ptr->reserved <<
" "
462 MemoryRegion *memory_region = &(block_region->memory);
464 block_region->memory.handle =
nullptr;
467 MemoryRequest split_request = request;
468 split_request.size = block_region->
memory.
size - request.size;
469 split_request.offset = block_region->memory.offset + request.size;
471#ifdef DEBUG_RUNTIME_INTERNAL
473 <<
"current region (offset=" << (
int32_t)block_region->memory.offset <<
" size=" << (
int32_t)(block_region->memory.size) <<
" bytes) "
474 <<
"to create empty region (offset=" << (
int32_t)split_request.offset <<
" size=" << (
int32_t)(split_request.size) <<
" bytes)";
476 BlockRegion *next_region = block_region->next_ptr;
477 BlockRegion *empty_region = create_block_region(
user_context, split_request);
480 empty_region->next_ptr = next_region;
482 next_region->prev_ptr = empty_region;
484 empty_region->prev_ptr = block_region;
485 block_region->next_ptr = empty_region;
486 block_region->memory.size -= empty_region->memory.size;
490BlockRegion *RegionAllocator::create_block_region(
void *
user_context,
const MemoryRequest &request) {
491#ifdef DEBUG_RUNTIME_INTERNAL
492 debug(
user_context) <<
"RegionAllocator: Creating block region request ("
494 <<
"offset=" << (
uint32_t)request.offset <<
" "
495 <<
"size=" << (
uint32_t)request.size <<
" "
496 <<
"alignment=" << (
uint32_t)request.properties.alignment <<
" "
497 <<
"dedicated=" << (request.dedicated ?
"true" :
"false") <<
" "
503 MemoryRequest region_request = request;
506#ifdef DEBUG_RUNTIME_INTERNAL
507 debug(
user_context) <<
"RegionAllocator: Failed to conform request for new block region!\n";
512 if (region_request.size == 0) {
513#ifdef DEBUG_RUNTIME_INTERNAL
514 debug(
user_context) <<
"RegionAllocator: Failed to allocate new block region ... region size was zero!\n";
519 BlockRegion *block_region =
static_cast<BlockRegion *
>(arena->
reserve(
user_context,
true));
520 if (block_region ==
nullptr) {
521#ifdef DEBUG_RUNTIME_INTERNAL
522 debug(
user_context) <<
"RegionAllocator: Failed to allocate new block region!\n";
527 block_region->memory.handle =
nullptr;
528 block_region->memory.offset = region_request.offset;
529 block_region->memory.size = region_request.size;
530 block_region->memory.properties = region_request.properties;
531 block_region->memory.dedicated = region_request.dedicated;
533 block_region->block_ptr = block;
534 block_region->usage_count = 0;
536#ifdef DEBUG_RUNTIME_INTERNAL
537 debug(
user_context) <<
"RegionAllocator: Created block region allocation ("
539 <<
"block_ptr=" << (
void *)block_region->block_ptr <<
" "
540 <<
"block_region=" << (
void *)block_region <<
" "
541 <<
"memory_offset=" << (
uint32_t)(block_region->memory.offset) <<
" "
542 <<
"memory_size=" << (
uint32_t)(block_region->memory.size) <<
" "
549int RegionAllocator::release_block_region(
void *
user_context, BlockRegion *block_region) {
550#ifdef DEBUG_RUNTIME_INTERNAL
551 debug(
user_context) <<
"RegionAllocator: Releasing block region ("
553 <<
"block_ptr=" << ((block_region) ? ((
void *)block_region->block_ptr) :
nullptr) <<
" "
554 <<
"block_region=" << (
void *)block_region <<
" "
555 <<
"usage_count=" << ((block_region) ? (
uint32_t)(block_region->usage_count) : 0) <<
" "
556 <<
"memory_offset=" << ((block_region) ? (
uint32_t)(block_region->memory.offset) : 0) <<
" "
557 <<
"memory_size=" << ((block_region) ? (
uint32_t)(block_region->memory.size) : 0) <<
" "
560 if (block_region ==
nullptr) {
564 if (block_region->usage_count > 0) {
570#ifdef DEBUG_RUNTIME_INTERNAL
572 <<
"block_ptr=" << (
void *)block_region->block_ptr <<
" "
573 <<
"block_region=" << (
void *)block_region <<
" "
574 <<
"memory_offset=" << (
uint32_t)(block_region->memory.offset) <<
" "
575 <<
"memory_size=" << (
uint32_t)(block_region->memory.size) <<
" "
576 <<
"block_reserved=" << (
uint32_t)(block->
reserved - block_region->memory.size) <<
" "
580 block->
reserved -= block_region->memory.size;
586int RegionAllocator::destroy_block_region(
void *
user_context, BlockRegion *block_region) {
587#ifdef DEBUG_RUNTIME_INTERNAL
588 debug(
user_context) <<
"RegionAllocator: Destroying block region ("
590 <<
"block_region=" << (
void *)(block_region) <<
") ...";
593 block_region->usage_count = 0;
600int RegionAllocator::alloc_block_region(
void *
user_context, BlockRegion *block_region) {
601#ifdef DEBUG_RUNTIME_INTERNAL
603 <<
" size=" << (
int32_t)(block_region->memory.size)
604 <<
" offset=" << (
int32_t)block_region->memory.offset <<
")";
609 MemoryRegion *memory_region = &(block_region->memory);
610 if (memory_region->handle ==
nullptr) {
612 memory_region->is_owner =
true;
614#ifdef DEBUG_RUNTIME_INTERNAL
616 <<
"block_ptr=" << (
void *)block_region->block_ptr <<
" "
617 <<
"block_region=" << (
void *)block_region <<
" "
618 <<
"memory_offset=" << (
uint32_t)(block_region->memory.offset) <<
" "
619 <<
"memory_size=" << (
uint32_t)(block_region->memory.size) <<
" "
626#ifdef DEBUG_RUNTIME_INTERNAL
628 <<
"block_ptr=" << (
void *)block_region->block_ptr <<
" "
629 <<
"block_region=" << (
void *)block_region <<
" "
630 <<
"memory_offset=" << (
uint32_t)(block_region->memory.offset) <<
" "
631 <<
"memory_size=" << (
uint32_t)(block_region->memory.size) <<
" "
638 block->
reserved += block_region->memory.size;
643int RegionAllocator::free_block_region(
void *
user_context, BlockRegion *block_region) {
644#ifdef DEBUG_RUNTIME_INTERNAL
645 debug(
user_context) <<
"RegionAllocator: Freeing block region ("
647 <<
"block_ptr=" << (
void *)block_region->block_ptr <<
" "
648 <<
"block_region=" << (
void *)(block_region) <<
" "
649 <<
"memory_size=" << (
uint32_t)(block_region->memory.size) <<
" "
650 <<
"status=" << (
uint32_t)block_region->status <<
" "
651 <<
"usage_count=" << (
uint32_t)block_region->usage_count <<
" "
655 if ((block_region->usage_count == 0) && (block_region->memory.handle !=
nullptr)) {
656#ifdef DEBUG_RUNTIME_INTERNAL
658 <<
"block_ptr=" << (
void *)block_region->block_ptr <<
" "
659 <<
"block_region=" << (
void *)block_region <<
" "
660 <<
"memory_size=" << (
uint32_t)(block_region->memory.size) <<
" "
666 MemoryRegion *memory_region = &(block_region->memory);
668 block_region->memory.handle =
nullptr;
670 block_region->usage_count = 0;
676#ifdef DEBUG_RUNTIME_INTERNAL
677 debug(
user_context) <<
"RegionAllocator: Releasing all regions ("
678 <<
"user_context=" << (
void *)(
user_context) <<
") ...";
682 while (block_region !=
nullptr) {
687 block_region = block_region->
next_ptr;
693#ifdef DEBUG_RUNTIME_INTERNAL
694 debug(
user_context) <<
"RegionAllocator: Collecting free block regions ("
695 <<
"user_context=" << (
void *)(
user_context) <<
") ...";
703 <<
"block_ptr=" << (
void *)block <<
" "
708 bool has_collected =
false;
710 while (block_region !=
nullptr) {
711#ifdef DEBUG_RUNTIME_INTERNAL
714 <<
"block_ptr=" << (
void *)block_region->
block_ptr <<
" "
715 <<
"block_region=" << (
void *)block_region <<
" "
723 if (can_coalesce(block_region)) {
724#ifdef DEBUG_RUNTIME_INTERNAL
727 <<
"block_ptr=" << (
void *)block_region->
block_ptr <<
" "
728 <<
"block_region=" << (
void *)block_region <<
" "
733 block_region = coalesce_block_regions(
user_context, block_region);
734 has_collected =
true;
736#ifdef DEBUG_RUNTIME_INTERNAL
740#ifdef DEBUG_RUNTIME_INTERNAL
741 available_bytes += is_available(block_region) ? block_region->
memory.
size : 0;
746 block_region = block_region->
next_ptr;
748#ifdef DEBUG_RUNTIME_INTERNAL
750 <<
"block_ptr=" << (
void *)block <<
" "
751 <<
"total_count=" << (
uint32_t)(collected_count + remaining_count) <<
" "
753 <<
"scanned_bytes=" << (
uint32_t)(scanned_bytes) <<
" "
754 <<
"available_bytes=" << (
uint32_t)(available_bytes) <<
" "
759#ifdef DEBUG_RUNTIME_INTERNAL
761 <<
"block_ptr=" << (
void *)block <<
" "
762 <<
"collected_count=" << (
uint32_t)collected_count <<
" "
763 <<
"remaining_count=" << (
uint32_t)remaining_count <<
" "
768 return has_collected;
772#ifdef DEBUG_RUNTIME_INTERNAL
773 debug(
user_context) <<
"RegionAllocator: Destroying all block regions ("
774 <<
"user_context=" << (
void *)(
user_context) <<
") ...";
776 if (block->
regions !=
nullptr) {
781 block_region =
nullptr;
784 block_region = block_region->
next_ptr;
792 if (arena !=
nullptr) {
821size_t RegionAllocator::region_count(
void *
user_context)
const {
822 if (block ==
nullptr) {
826 for (BlockRegion
const *region = block->
regions; !is_last_block_region(
user_context, region); region = region->next_ptr) {
This file declares the routines used by Halide internally in its runtime.
void * reserve(void *user_context, bool initialize=false)
static MemoryArena * create(void *user_context, const Config &config, const SystemMemoryAllocatorFns &allocator=default_allocator())
static constexpr uint32_t default_capacity
static void destroy(void *user_context, MemoryArena *arena)
void reclaim(void *user_context, void *ptr)
Allocator class interface for sub-allocating a contiguous memory block into smaller regions of memory...
MemoryRegion * reserve(void *user_context, const MemoryRequest &request)
RegionAllocator & operator=(const RegionAllocator &)=delete
RegionAllocator(const RegionAllocator &)=delete
static int destroy(void *user_context, RegionAllocator *region_allocator)
int conform(void *user_context, MemoryRequest *request) const
static RegionAllocator * find_allocator(void *user_context, MemoryRegion *memory_region)
int retain(void *user_context, MemoryRegion *memory_region)
bool collect(void *user_context)
~RegionAllocator()=delete
int reclaim(void *user_context, MemoryRegion *memory_region)
int release(void *user_context, MemoryRegion *memory_region)
BlockResource * block_resource() const
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)
ALWAYS_INLINE size_t conform_alignment(size_t requested, size_t required)
ALWAYS_INLINE size_t conform_size(size_t offset, size_t size, size_t alignment, size_t nearest_multiple)
ALWAYS_INLINE size_t aligned_offset(size_t offset, size_t alignment)
This file defines the class FunctionDAG, which is our representation of a Halide pipeline,...
@ Internal
Not visible externally, similar to 'static' linkage in C.
unsigned __INT64_TYPE__ uint64_t
signed __INT32_TYPE__ int32_t
unsigned __INT32_TYPE__ uint32_t
#define halide_abort_if_false(user_context, cond)
BlockResource * block_ptr
RegionAllocator * allocator
MemoryProperties properties
MemoryVisibility visibility
DeallocateRegionFn deallocate
AllocateRegionFn allocate
ConformBlockRegionFn conform
MemoryProperties properties
MemoryRegionAllocatorFns region
SystemMemoryAllocatorFns system
DeallocateSystemFn deallocate
AllocateSystemFn allocate