From 3498472613db1fe86ccdeb2d84e198dea0775c2b Mon Sep 17 00:00:00 2001 From: Wojciech Jablonski Date: Mon, 27 Oct 2025 17:55:46 +0100 Subject: [PATCH] vmh: add virtual heap stats Option that allows collecting statistics on individual allocator of a virtual memory heap. By defaults the following stats are output per allocator: 1. Maximal number of blocks allocated at any given moment during the heap lifespan 2. How many times the allocator was full, and an allocation had to be redirected to another allocator (with greater/less optimal block size) By default, stats are outputted only on allocation error This feature depends on SYS_MEM_BLOCKS_RUNTIME_STATS Zephyr option and hence is controlled by the same config option Signed-off-by: Wojciech Jablonski --- zephyr/include/sof/lib/regions_mm.h | 3 ++ zephyr/lib/alloc.c | 6 +++- zephyr/lib/regions_mm.c | 46 +++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/zephyr/include/sof/lib/regions_mm.h b/zephyr/include/sof/lib/regions_mm.h index 757094e32fcf..9e960e304b65 100644 --- a/zephyr/include/sof/lib/regions_mm.h +++ b/zephyr/include/sof/lib/regions_mm.h @@ -87,6 +87,9 @@ int vmh_free_heap(struct vmh_heap *heap); int vmh_free(struct vmh_heap *heap, void *ptr); void vmh_get_default_heap_config(const struct sys_mm_drv_region *region, struct vmh_heap_config *cfg); +#ifdef CONFIG_SYS_MEM_BLOCKS_RUNTIME_STATS +void vmh_log_stats(struct vmh_heap *heap); +#endif /** * @brief Checks if ptr is in range of given memory range * diff --git a/zephyr/lib/alloc.c b/zephyr/lib/alloc.c index 946a07b9124a..2c5754f92b27 100644 --- a/zephyr/lib/alloc.c +++ b/zephyr/lib/alloc.c @@ -292,8 +292,12 @@ static void *virtual_heap_alloc(struct vmh_heap *heap, uint32_t flags, size_t by { void *mem = vmh_alloc(heap, bytes); - if (!mem) + if (!mem) { +#ifdef CONFIG_SYS_MEM_BLOCKS_RUNTIME_STATS + vmh_log_stats(heap); +#endif return NULL; + } assert(align == 0 || IS_ALIGNED(mem, align)); diff --git a/zephyr/lib/regions_mm.c b/zephyr/lib/regions_mm.c index c9b307b8f298..9b8db4b504af 100644 --- a/zephyr/lib/regions_mm.c +++ b/zephyr/lib/regions_mm.c @@ -10,6 +10,7 @@ #if defined(CONFIG_MM_DRV) #include +LOG_MODULE_DECLARE(mem_allocator, CONFIG_SOF_LOG_LEVEL); /** @struct vmh_heap * @@ -32,6 +33,10 @@ struct vmh_heap { const struct sys_mm_drv_region *virtual_region; struct sys_mem_blocks *physical_blocks_allocators[MAX_MEMORY_ALLOCATORS_COUNT]; struct sys_bitarray *allocation_sizes[MAX_MEMORY_ALLOCATORS_COUNT]; +#ifdef CONFIG_SYS_MEM_BLOCKS_RUNTIME_STATS + unsigned int out_of_blocks[MAX_MEMORY_ALLOCATORS_COUNT]; + bool logged; +#endif bool allocating_continuously; }; @@ -398,6 +403,9 @@ static void *_vmh_alloc(struct vmh_heap *heap, uint32_t alloc_size) int mem_block_iterator, allocation_error_code = -ENOMEM; size_t allocation_bitarray_offset, block_count = 0, block_size = 0, allocation_bitarray_position = 0; +#ifdef CONFIG_SYS_MEM_BLOCKS_RUNTIME_STATS + bool first_match = true; +#endif /* We will gather error code when allocating on physical block * allocators. @@ -487,6 +495,11 @@ static void *_vmh_alloc(struct vmh_heap *heap, uint32_t alloc_size) sys_bitarray_set_region(heap->allocation_sizes[mem_block_iterator], block_count - 1, allocation_bitarray_position); break; +#ifdef CONFIG_SYS_MEM_BLOCKS_RUNTIME_STATS + } else if (first_match) { + ++heap->out_of_blocks[mem_block_iterator]; + first_match = false; +#endif } } @@ -699,6 +712,39 @@ int vmh_free(struct vmh_heap *heap, void *ptr) return ret; } +#ifdef CONFIG_SYS_MEM_BLOCKS_RUNTIME_STATS +/** + * @brief Print stats on heap usage per allocator + * + * @param heap pointer to a heap for which statistics are collected + */ +void vmh_log_stats(struct vmh_heap *heap) +{ + if (heap->logged) + return; + + LOG_INF("Virtual heap stats per allocator"); + LOG_INF(" ID | Total | Max use| Times run out of blocks"); + + for (int idx = 0; idx < MAX_MEMORY_ALLOCATORS_COUNT; idx++) { + if (!heap->physical_blocks_allocators[idx]) + continue; + + struct sys_memory_stats stats = {0}; + + sys_mem_blocks_runtime_stats_get(heap->physical_blocks_allocators[idx], &stats); + + size_t block_size = 1 << heap->physical_blocks_allocators[idx]->info.blk_sz_shift; + size_t block_num = heap->physical_blocks_allocators[idx]->info.num_blocks; + + LOG_INF("%7d| %7u| %7u| %7u", idx, block_num, + (stats.max_allocated_bytes / block_size), + heap->out_of_blocks[idx]); + } + heap->logged = true; +} +#endif + /** * @brief Get default configuration for heap *