diff --git a/include/zephyr/sys/sys_heap.h b/include/zephyr/sys/sys_heap.h index f01bae189e6..33d989576a5 100644 --- a/include/zephyr/sys/sys_heap.h +++ b/include/zephyr/sys/sys_heap.h @@ -267,6 +267,24 @@ void sys_heap_stress(void *(*alloc_fn)(void *arg, size_t bytes), */ void sys_heap_print_info(struct sys_heap *heap, bool dump_chunks); +/** @brief Save the heap pointer + * + * The heap pointer is saved into an internal array, if there is space. + * + * @param heap Heap to save + * @return -EINVAL if null pointer or array is full, otherwise 0 + */ +int sys_heap_array_save(struct sys_heap *heap); + +/** @brief Get the array of saved heap pointers + * + * Returns the pointer to the array of heap pointers. + * + * @param heap Heap array + * @return -EINVAL if null pointer, otherwise number of saved pointers + */ +int sys_heap_array_get(struct sys_heap ***heap); + /** * @} */ diff --git a/lib/heap/CMakeLists.txt b/lib/heap/CMakeLists.txt index f3853fc5b7d..1e4a3391388 100644 --- a/lib/heap/CMakeLists.txt +++ b/lib/heap/CMakeLists.txt @@ -11,3 +11,4 @@ zephyr_sources_ifdef(CONFIG_SYS_HEAP_STRESS heap_stress.c) zephyr_sources_ifdef(CONFIG_SHARED_MULTI_HEAP shared_multi_heap.c) zephyr_sources_ifdef(CONFIG_MULTI_HEAP multi_heap.c) zephyr_sources_ifdef(CONFIG_HEAP_LISTENER heap_listener.c) +zephyr_sources_ifdef(CONFIG_SYS_HEAP_ARRAY_SIZE heap_array.c) diff --git a/lib/heap/Kconfig b/lib/heap/Kconfig index 89ede278006..0d97da3e340 100644 --- a/lib/heap/Kconfig +++ b/lib/heap/Kconfig @@ -52,6 +52,18 @@ config SYS_HEAP_RUNTIME_STATS help Gather system heap runtime statistics. +config SYS_HEAP_ARRAY_SIZE + int "Size of array to store heap pointers" + default 0 + help + The size of the internal array to store heap pointers. The array + is filled with a heap pointer on every sys_heap_init() call. + One can then iterate through the array to get all heaps statistics + and to sum up the total memory allocated for all heaps. + + The default array size is zero, which disables the feature. + To enable the feature, assign a value greater than zero. + config SYS_HEAP_LISTENER bool "sys_heap event notifications" select HEAP_LISTENER diff --git a/lib/heap/heap.c b/lib/heap/heap.c index 7fb6884c90e..517c43f5085 100644 --- a/lib/heap/heap.c +++ b/lib/heap/heap.c @@ -517,6 +517,10 @@ void sys_heap_init(struct sys_heap *heap, void *mem, size_t bytes) h->max_allocated_bytes = 0; #endif +#if CONFIG_SYS_HEAP_ARRAY_SIZE + sys_heap_array_save(heap); +#endif + int nb_buckets = bucket_idx(h, heap_sz) + 1; chunksz_t chunk0_size = chunksz(sizeof(struct z_heap) + nb_buckets * sizeof(struct z_heap_bucket)); diff --git a/lib/heap/heap_array.c b/lib/heap/heap_array.c new file mode 100644 index 00000000000..dc1b3a4535d --- /dev/null +++ b/lib/heap/heap_array.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025 Silicon Laboratories Inc. www.silabs.com + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include + +static size_t i; +static struct sys_heap *heaps[CONFIG_SYS_HEAP_ARRAY_SIZE]; + +int sys_heap_array_save(struct sys_heap *heap) +{ + if (heap == NULL) { + return -EINVAL; + } + + if (i < CONFIG_SYS_HEAP_ARRAY_SIZE) { + heaps[i++] = heap; + } else { + return -EINVAL; + } + + return 0; +} + +int sys_heap_array_get(struct sys_heap ***heap) +{ + if (heap == NULL) { + return -EINVAL; + } + + *heap = heaps; + + return i; +} diff --git a/samples/basic/sys_heap/prj.conf b/samples/basic/sys_heap/prj.conf index 2ffddad1e9b..0c486563862 100644 --- a/samples/basic/sys_heap/prj.conf +++ b/samples/basic/sys_heap/prj.conf @@ -1 +1,2 @@ CONFIG_SYS_HEAP_RUNTIME_STATS=y +CONFIG_SYS_HEAP_ARRAY_SIZE=4 diff --git a/samples/basic/sys_heap/src/main.c b/samples/basic/sys_heap/src/main.c index 33f72302688..e59ab749283 100644 --- a/samples/basic/sys_heap/src/main.c +++ b/samples/basic/sys_heap/src/main.c @@ -9,10 +9,13 @@ #define HEAP_SIZE 256 +K_HEAP_DEFINE(my_kernel_heap, HEAP_SIZE); + static char heap_mem[HEAP_SIZE]; static struct sys_heap heap; -static void print_sys_memory_stats(void); +static void print_sys_memory_stats(struct sys_heap *); +static void print_all_heaps(void); int main(void) { @@ -21,26 +24,42 @@ int main(void) printk("System heap sample\n\n"); sys_heap_init(&heap, heap_mem, HEAP_SIZE); - print_sys_memory_stats(); + print_sys_memory_stats(&heap); p = sys_heap_alloc(&heap, 150); - print_sys_memory_stats(); + print_sys_memory_stats(&heap); p = sys_heap_realloc(&heap, p, 100); - print_sys_memory_stats(); + print_sys_memory_stats(&heap); sys_heap_free(&heap, p); - print_sys_memory_stats(); + print_sys_memory_stats(&heap); + + print_all_heaps(); return 0; } -static void print_sys_memory_stats(void) +static void print_sys_memory_stats(struct sys_heap *hp) { struct sys_memory_stats stats; - sys_heap_runtime_stats_get(&heap, &stats); + sys_heap_runtime_stats_get(hp, &stats); printk("allocated %zu, free %zu, max allocated %zu, heap size %u\n", stats.allocated_bytes, stats.free_bytes, stats.max_allocated_bytes, HEAP_SIZE); } + +static void print_all_heaps(void) +{ + struct sys_heap **ha; + size_t i, n; + + n = sys_heap_array_get(&ha); + printk("There are %zu heaps allocated:\n", n); + + for (i = 0; i < n; i++) { + printk("\t%zu - address %p ", i, ha[i]); + print_sys_memory_stats(ha[i]); + } +}