lib/os: add statistics tracking to mem_blocks
Both the current and maximum number of allocations in a given memory blocked are tracked (and can be queried) when the CONFIG_SYS_MEM_BLOCKS_RUNTIME_STATS Kconfig option is selected. Signed-off-by: Peter Mitsis <peter.mitsis@intel.com>
This commit is contained in:
parent
ee190f49c2
commit
d061366f54
4 changed files with 159 additions and 8 deletions
|
|
@ -23,6 +23,7 @@ extern "C" {
|
|||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/math/ilog2.h>
|
||||
#include <zephyr/sys/bitarray.h>
|
||||
#include <zephyr/sys/mem_stats.h>
|
||||
|
||||
#define MAX_MULTI_ALLOCATORS 8
|
||||
|
||||
|
|
@ -93,6 +94,14 @@ struct sys_mem_blocks {
|
|||
/* Bitmap of allocated blocks */
|
||||
sys_bitarray_t *bitmap;
|
||||
|
||||
#ifdef CONFIG_SYS_MEM_BLOCKS_RUNTIME_STATS
|
||||
/* Spinlock guarding access to memory block internals */
|
||||
struct k_spinlock lock;
|
||||
|
||||
uint32_t used_blocks;
|
||||
uint32_t max_used_blocks;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
struct sys_multi_mem_blocks {
|
||||
|
|
@ -285,6 +294,34 @@ int sys_mem_blocks_free(sys_mem_blocks_t *mem_block, size_t count,
|
|||
*/
|
||||
int sys_mem_blocks_free_contiguous(sys_mem_blocks_t *mem_block, void *block, size_t count);
|
||||
|
||||
#ifdef CONFIG_SYS_MEM_BLOCKS_RUNTIME_STATS
|
||||
/**
|
||||
* @brief Get the runtime statistics of a memory block
|
||||
*
|
||||
* This function retrieves the runtime stats for the specified memory block
|
||||
* @a mem_block and copies it into the memory pointed to by @a stats.
|
||||
*
|
||||
* @param mem_block Pointer to system memory block
|
||||
* @param stats Pointer to struct to copy statistics into
|
||||
*
|
||||
* @return -EINVAL if NULL pointer was passed, otherwise 0
|
||||
*/
|
||||
int sys_mem_blocks_runtime_stats_get(sys_mem_blocks_t *mem_block,
|
||||
struct sys_memory_stats *stats);
|
||||
|
||||
/**
|
||||
* @brief Reset the maximum memory block usage
|
||||
*
|
||||
* This routine resets the maximum memory usage in the specified memory
|
||||
* block @a mem_block to match that block's current memory usage.
|
||||
*
|
||||
* @param mem_block Pointer to system memory block
|
||||
*
|
||||
* @return -EINVAL if NULL pointer was passed, otherwise 0
|
||||
*/
|
||||
int sys_mem_blocks_runtime_stats_reset_max(sys_mem_blocks_t *mem_block);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Initialize multi memory blocks allocator group
|
||||
*
|
||||
|
|
|
|||
34
include/zephyr/sys/mem_stats.h
Normal file
34
include/zephyr/sys/mem_stats.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @brief Memory Statistics
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_INCLUDE_SYS_MEM_STATS_H_
|
||||
#define ZEPHYR_INCLUDE_SYS_MEM_STATS_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/* A common structure used to report runtime memory usage statistics */
|
||||
|
||||
struct sys_memory_stats {
|
||||
size_t free_bytes;
|
||||
size_t allocated_bytes;
|
||||
size_t max_allocated_bytes;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_SYS_MEM_STATS_H_ */
|
||||
|
|
@ -125,4 +125,12 @@ config SYS_MEM_BLOCKS_LISTENER
|
|||
This allows application to listen for memory blocks allocator
|
||||
events, such as memory allocation and de-allocation.
|
||||
|
||||
config SYS_MEM_BLOCKS_RUNTIME_STATS
|
||||
bool "Memory blocks runtime statistics"
|
||||
depends on SYS_MEM_BLOCKS
|
||||
help
|
||||
This option enables the tracking and reporting of the memory
|
||||
blocks statistics related to the current and maximum number
|
||||
of allocations in a given memory block.
|
||||
|
||||
endmenu
|
||||
|
|
|
|||
|
|
@ -18,18 +18,31 @@ static void *alloc_blocks(sys_mem_blocks_t *mem_block, size_t num_blocks)
|
|||
uint8_t *blk;
|
||||
void *ret = NULL;
|
||||
|
||||
#ifdef CONFIG_SYS_MEM_BLOCKS_RUNTIME_STATS
|
||||
k_spinlock_key_t key = k_spin_lock(&mem_block->lock);
|
||||
#endif
|
||||
|
||||
/* Find an unallocated block */
|
||||
r = sys_bitarray_alloc(mem_block->bitmap, num_blocks, &offset);
|
||||
if (r != 0) {
|
||||
goto out;
|
||||
if (r == 0) {
|
||||
|
||||
#ifdef CONFIG_SYS_MEM_BLOCKS_RUNTIME_STATS
|
||||
mem_block->used_blocks += (uint32_t)num_blocks;
|
||||
|
||||
if (mem_block->max_used_blocks < mem_block->used_blocks) {
|
||||
mem_block->max_used_blocks = mem_block->used_blocks;
|
||||
}
|
||||
|
||||
k_spin_unlock(&mem_block->lock, key);
|
||||
#endif
|
||||
|
||||
/* Calculate the start address of the newly allocated block */
|
||||
|
||||
blk = mem_block->buffer + (offset << mem_block->blk_sz_shift);
|
||||
|
||||
ret = blk;
|
||||
}
|
||||
|
||||
/* Calculate the start address of the newly allocated block */
|
||||
blk = mem_block->buffer + (offset << mem_block->blk_sz_shift);
|
||||
|
||||
ret = blk;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -51,8 +64,19 @@ static int free_blocks(sys_mem_blocks_t *mem_block, void *ptr, size_t num_blocks
|
|||
goto out;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SYS_MEM_BLOCKS_RUNTIME_STATS
|
||||
k_spinlock_key_t key = k_spin_lock(&mem_block->lock);
|
||||
#endif
|
||||
ret = sys_bitarray_free(mem_block->bitmap, num_blocks, offset);
|
||||
|
||||
#ifdef CONFIG_SYS_MEM_BLOCKS_RUNTIME_STATS
|
||||
if (ret == 0) {
|
||||
mem_block->used_blocks -= (uint32_t) num_blocks;
|
||||
}
|
||||
|
||||
k_spin_unlock(&mem_block->lock, key);
|
||||
#endif
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -163,12 +187,30 @@ int sys_mem_blocks_get(sys_mem_blocks_t *mem_block, void *in_block, size_t count
|
|||
goto out;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SYS_MEM_BLOCKS_RUNTIME_STATS
|
||||
k_spinlock_key_t key = k_spin_lock(&mem_block->lock);
|
||||
#endif
|
||||
|
||||
ret = sys_bitarray_test_and_set_region(mem_block->bitmap, count, offset, true);
|
||||
|
||||
if (ret != 0) {
|
||||
#ifdef CONFIG_SYS_MEM_BLOCKS_RUNTIME_STATS
|
||||
k_spin_unlock(&mem_block->lock, key);
|
||||
#endif
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SYS_MEM_BLOCKS_RUNTIME_STATS
|
||||
mem_block->used_blocks += (uint32_t)count;
|
||||
|
||||
if (mem_block->max_used_blocks < mem_block->used_blocks) {
|
||||
mem_block->max_used_blocks = mem_block->used_blocks;
|
||||
}
|
||||
|
||||
k_spin_unlock(&mem_block->lock, key);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYS_MEM_BLOCKS_LISTENER
|
||||
heap_listener_notify_alloc(HEAP_ID_FROM_POINTER(mem_block),
|
||||
in_block, count << mem_block->blk_sz_shift);
|
||||
|
|
@ -354,3 +396,33 @@ int sys_multi_mem_blocks_free(sys_multi_mem_blocks_t *group,
|
|||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SYS_MEM_BLOCKS_RUNTIME_STATS
|
||||
int sys_mem_blocks_runtime_stats_get(sys_mem_blocks_t *mem_block,
|
||||
struct sys_memory_stats *stats)
|
||||
{
|
||||
if ((mem_block == NULL) || (stats == NULL)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
stats->allocated_bytes = mem_block->used_blocks <<
|
||||
mem_block->blk_sz_shift;
|
||||
stats->free_bytes = (mem_block->num_blocks << mem_block->blk_sz_shift) -
|
||||
stats->allocated_bytes;
|
||||
stats->max_allocated_bytes = mem_block->max_used_blocks <<
|
||||
mem_block->blk_sz_shift;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_mem_blocks_runtime_stats_reset_max(sys_mem_blocks_t *mem_block)
|
||||
{
|
||||
if (mem_block == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mem_block->max_used_blocks = mem_block->used_blocks;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in a new issue