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 <ivan.pankratov@silabs.com>
This commit is contained in:
Ivan Pankratov 2025-01-16 12:05:09 +00:00 committed by Benjamin Cabé
parent b8200f29ed
commit 257d9d45ba
7 changed files with 98 additions and 7 deletions

View file

@ -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);
/**
* @}
*/

View file

@ -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)

View file

@ -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

View file

@ -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));

36
lib/heap/heap_array.c Normal file
View file

@ -0,0 +1,36 @@
/*
* Copyright (c) 2025 Silicon Laboratories Inc. www.silabs.com
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/sys/sys_heap.h>
#include <zephyr/kernel.h>
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;
}

View file

@ -1 +1,2 @@
CONFIG_SYS_HEAP_RUNTIME_STATS=y
CONFIG_SYS_HEAP_ARRAY_SIZE=4

View file

@ -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]);
}
}