From 257d9d45ba0ae8fb08f44faff18a72bd48682081 Mon Sep 17 00:00:00 2001 From: Ivan Pankratov Date: Thu, 16 Jan 2025 12:05:09 +0000 Subject: [PATCH] kernel: sys_heap: stats: save heap pointers to an array during init To request heap statistics, a pointer to a heap structure is required. This is straightforward for a user-defined heap. However, such a pointer is not known for heaps created by other components or libraries, like libc. Therefore, it is not possible to calculate the total heap memory. The proposed solution is to use an array of pointers, which is filled in on every sys_heap_init() call. One can then iterate through it to sum up the total memory allocated for all heaps. The array size is configurable. The default array size is zero, which means the feature is disabled. Any other integer greater then zero defines the array size and enables the feature. A list of pointers instead of an array could be another approach, but it requeres a heap, which is not always available. Signed-off-by: Ivan Pankratov --- include/zephyr/sys/sys_heap.h | 18 ++++++++++++++++ lib/heap/CMakeLists.txt | 1 + lib/heap/Kconfig | 12 +++++++++++ lib/heap/heap.c | 4 ++++ lib/heap/heap_array.c | 36 +++++++++++++++++++++++++++++++ samples/basic/sys_heap/prj.conf | 1 + samples/basic/sys_heap/src/main.c | 33 ++++++++++++++++++++++------ 7 files changed, 98 insertions(+), 7 deletions(-) create mode 100644 lib/heap/heap_array.c 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]); + } +}