/* * Copyright (C) 2024 TU Dresden * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level * directory for more details. */ /** * @{ * * @file * @brief monitor heap memory usage (calls to malloc/realloc/free) * @author Mikolai Gütschow */ #include #include #include "architecture.h" #include "assert.h" #include "cpu.h" #include "irq.h" #include "mutex.h" #include "malloc_monitor.h" #include "malloc_monitor_internal.h" #ifndef CONFIG_MODULE_SYS_MALLOC_MONITOR_SIZE #define CONFIG_MODULE_SYS_MALLOC_MONITOR_SIZE 100 #endif #ifndef CONFIG_MODULE_SYS_MALLOC_MONITOR_VERBOSE #define CONFIG_MODULE_SYS_MALLOC_MONITOR_VERBOSE 0 #endif static struct { void *addr[CONFIG_MODULE_SYS_MALLOC_MONITOR_SIZE]; size_t size[CONFIG_MODULE_SYS_MALLOC_MONITOR_SIZE]; size_t current; size_t high_watermark; } malloc_monitor = { .addr = {NULL}, .current = 0, .high_watermark = 0, }; /* guards access to malloc_monitor */ static mutex_t _lock; void malloc_monitor_add(void *ptr, size_t size, uinttxtptr_t pc, char *func_prefix) { if (ptr == NULL) { return; } #if CONFIG_MODULE_SYS_MALLOC_MONITOR_VERBOSE printf("%salloc(%" PRIuSIZE ") @ 0x%" PRIxTXTPTR " returned %p\n", func_prefix, size, pc, ptr); #endif assert(!irq_is_in()); mutex_lock(&_lock); for (uint8_t i=0; i malloc_monitor.high_watermark) { malloc_monitor.high_watermark = malloc_monitor.current; } mutex_unlock(&_lock); return; } } mutex_unlock(&_lock); printf("malloc_monitor: maximum number of pointers to be monitored " "(as set by CONFIG_MODULE_SYS_MALLOC_MONITOR_SIZE) exceeded.\n"); (void)func_prefix; (void)pc; } void malloc_monitor_rm(void *ptr, uinttxtptr_t pc) { if (ptr == NULL) { return; } #if CONFIG_MODULE_SYS_MALLOC_MONITOR_VERBOSE printf("malloc_monitor: free(%p) @ 0x%" PRIxTXTPTR " \n", ptr, pc); #endif assert(!irq_is_in()); mutex_lock(&_lock); for (uint8_t i=0; i size_old) { malloc_monitor.current += size_new - size_old; if (malloc_monitor.current > malloc_monitor.high_watermark) { malloc_monitor.high_watermark = malloc_monitor.current; } } else { malloc_monitor.current -= size_old - size_new; } mutex_unlock(&_lock); return; } } mutex_unlock(&_lock); printf("malloc_monitor: realloc(%p) @ 0x%" PRIxTXTPTR " invalid\n", ptr_old, pc); } size_t malloc_monitor_get_usage_current(void) { assert(!irq_is_in()); mutex_lock(&_lock); size_t ret = malloc_monitor.current; mutex_unlock(&_lock); return ret; } size_t malloc_monitor_get_usage_high_watermark(void) { assert(!irq_is_in()); mutex_lock(&_lock); size_t ret = malloc_monitor.high_watermark; mutex_unlock(&_lock); return ret; } void malloc_monitor_reset_high_watermark(void) { assert(!irq_is_in()); mutex_lock(&_lock); malloc_monitor.high_watermark = malloc_monitor.current; mutex_unlock(&_lock); } /** @} */