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:
parent
b8200f29ed
commit
257d9d45ba
7 changed files with 98 additions and 7 deletions
|
|
@ -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);
|
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);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -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_SHARED_MULTI_HEAP shared_multi_heap.c)
|
||||||
zephyr_sources_ifdef(CONFIG_MULTI_HEAP 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_HEAP_LISTENER heap_listener.c)
|
||||||
|
zephyr_sources_ifdef(CONFIG_SYS_HEAP_ARRAY_SIZE heap_array.c)
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,18 @@ config SYS_HEAP_RUNTIME_STATS
|
||||||
help
|
help
|
||||||
Gather system heap runtime statistics.
|
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
|
config SYS_HEAP_LISTENER
|
||||||
bool "sys_heap event notifications"
|
bool "sys_heap event notifications"
|
||||||
select HEAP_LISTENER
|
select HEAP_LISTENER
|
||||||
|
|
|
||||||
|
|
@ -517,6 +517,10 @@ void sys_heap_init(struct sys_heap *heap, void *mem, size_t bytes)
|
||||||
h->max_allocated_bytes = 0;
|
h->max_allocated_bytes = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG_SYS_HEAP_ARRAY_SIZE
|
||||||
|
sys_heap_array_save(heap);
|
||||||
|
#endif
|
||||||
|
|
||||||
int nb_buckets = bucket_idx(h, heap_sz) + 1;
|
int nb_buckets = bucket_idx(h, heap_sz) + 1;
|
||||||
chunksz_t chunk0_size = chunksz(sizeof(struct z_heap) +
|
chunksz_t chunk0_size = chunksz(sizeof(struct z_heap) +
|
||||||
nb_buckets * sizeof(struct z_heap_bucket));
|
nb_buckets * sizeof(struct z_heap_bucket));
|
||||||
|
|
|
||||||
36
lib/heap/heap_array.c
Normal file
36
lib/heap/heap_array.c
Normal 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;
|
||||||
|
}
|
||||||
|
|
@ -1 +1,2 @@
|
||||||
CONFIG_SYS_HEAP_RUNTIME_STATS=y
|
CONFIG_SYS_HEAP_RUNTIME_STATS=y
|
||||||
|
CONFIG_SYS_HEAP_ARRAY_SIZE=4
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,13 @@
|
||||||
|
|
||||||
#define HEAP_SIZE 256
|
#define HEAP_SIZE 256
|
||||||
|
|
||||||
|
K_HEAP_DEFINE(my_kernel_heap, HEAP_SIZE);
|
||||||
|
|
||||||
static char heap_mem[HEAP_SIZE];
|
static char heap_mem[HEAP_SIZE];
|
||||||
static struct sys_heap heap;
|
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)
|
int main(void)
|
||||||
{
|
{
|
||||||
|
|
@ -21,26 +24,42 @@ int main(void)
|
||||||
printk("System heap sample\n\n");
|
printk("System heap sample\n\n");
|
||||||
|
|
||||||
sys_heap_init(&heap, heap_mem, HEAP_SIZE);
|
sys_heap_init(&heap, heap_mem, HEAP_SIZE);
|
||||||
print_sys_memory_stats();
|
print_sys_memory_stats(&heap);
|
||||||
|
|
||||||
p = sys_heap_alloc(&heap, 150);
|
p = sys_heap_alloc(&heap, 150);
|
||||||
print_sys_memory_stats();
|
print_sys_memory_stats(&heap);
|
||||||
|
|
||||||
p = sys_heap_realloc(&heap, p, 100);
|
p = sys_heap_realloc(&heap, p, 100);
|
||||||
print_sys_memory_stats();
|
print_sys_memory_stats(&heap);
|
||||||
|
|
||||||
sys_heap_free(&heap, p);
|
sys_heap_free(&heap, p);
|
||||||
print_sys_memory_stats();
|
print_sys_memory_stats(&heap);
|
||||||
|
|
||||||
|
print_all_heaps();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_sys_memory_stats(void)
|
static void print_sys_memory_stats(struct sys_heap *hp)
|
||||||
{
|
{
|
||||||
struct sys_memory_stats stats;
|
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",
|
printk("allocated %zu, free %zu, max allocated %zu, heap size %u\n",
|
||||||
stats.allocated_bytes, stats.free_bytes,
|
stats.allocated_bytes, stats.free_bytes,
|
||||||
stats.max_allocated_bytes, HEAP_SIZE);
|
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…
Reference in a new issue