Browse Source

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>
pull/84195/head
Ivan Pankratov 6 months ago committed by Benjamin Cabé
parent
commit
257d9d45ba
  1. 18
      include/zephyr/sys/sys_heap.h
  2. 1
      lib/heap/CMakeLists.txt
  3. 12
      lib/heap/Kconfig
  4. 4
      lib/heap/heap.c
  5. 36
      lib/heap/heap_array.c
  6. 1
      samples/basic/sys_heap/prj.conf
  7. 33
      samples/basic/sys_heap/src/main.c

18
include/zephyr/sys/sys_heap.h

@ -267,6 +267,24 @@ void sys_heap_stress(void *(*alloc_fn)(void *arg, size_t bytes), @@ -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);
/**
* @}
*/

1
lib/heap/CMakeLists.txt

@ -11,3 +11,4 @@ zephyr_sources_ifdef(CONFIG_SYS_HEAP_STRESS heap_stress.c) @@ -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)

12
lib/heap/Kconfig

@ -52,6 +52,18 @@ config SYS_HEAP_RUNTIME_STATS @@ -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

4
lib/heap/heap.c

@ -517,6 +517,10 @@ void sys_heap_init(struct sys_heap *heap, void *mem, size_t bytes) @@ -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

@ -0,0 +1,36 @@ @@ -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;
}

1
samples/basic/sys_heap/prj.conf

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

33
samples/basic/sys_heap/src/main.c

@ -9,10 +9,13 @@ @@ -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) @@ -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]);
}
}

Loading…
Cancel
Save