mirror of https://github.com/ARMmbed/mbed-os.git
Merge pull request #13909 from mikaleppanen/feature-wisun-dyn-mem-track
[feature-wisun] Add nanostack dynamic memory tracker and hooks to dynmem librarypull/14018/head
commit
9d23b7c55b
|
@ -5,6 +5,7 @@ source/libip6string/ip6tos.c \
|
||||||
source/libip6string/stoip6.c \
|
source/libip6string/stoip6.c \
|
||||||
source/libList/ns_list.c \
|
source/libList/ns_list.c \
|
||||||
source/nsdynmemLIB/nsdynmemLIB.c \
|
source/nsdynmemLIB/nsdynmemLIB.c \
|
||||||
|
source/nsdynmemtracker/nsdynmem_tracker_lib.c \
|
||||||
source/nvmHelper/ns_nvm_helper.c \
|
source/nvmHelper/ns_nvm_helper.c \
|
||||||
|
|
||||||
LIB := libservice.a
|
LIB := libservice.a
|
||||||
|
|
|
@ -37,6 +37,9 @@ extern "C" {
|
||||||
typedef size_t ns_mem_block_size_t; //external interface unsigned heap block size type
|
typedef size_t ns_mem_block_size_t; //external interface unsigned heap block size type
|
||||||
typedef size_t ns_mem_heap_size_t; //total heap size type.
|
typedef size_t ns_mem_heap_size_t; //total heap size type.
|
||||||
|
|
||||||
|
// Can be used to enable tracking of dynamic memory allocations
|
||||||
|
#include "nsdynmem_tracker.h"
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \enum heap_fail_t
|
* \enum heap_fail_t
|
||||||
* \brief Dynamically heap system failure call back event types.
|
* \brief Dynamically heap system failure call back event types.
|
||||||
|
@ -99,7 +102,9 @@ extern int ns_dyn_mem_region_add(void *region_ptr, ns_mem_heap_size_t region_siz
|
||||||
* \return 0, Free OK
|
* \return 0, Free OK
|
||||||
* \return <0, Free Fail
|
* \return <0, Free Fail
|
||||||
*/
|
*/
|
||||||
|
#if NSDYNMEM_TRACKER_ENABLED!=1
|
||||||
extern void ns_dyn_mem_free(void *heap_ptr);
|
extern void ns_dyn_mem_free(void *heap_ptr);
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Allocate temporary data.
|
* \brief Allocate temporary data.
|
||||||
|
@ -111,7 +116,9 @@ extern void ns_dyn_mem_free(void *heap_ptr);
|
||||||
* \return 0, Allocate Fail
|
* \return 0, Allocate Fail
|
||||||
* \return >0, Pointer to allocated data sector.
|
* \return >0, Pointer to allocated data sector.
|
||||||
*/
|
*/
|
||||||
|
#if NSDYNMEM_TRACKER_ENABLED!=1
|
||||||
extern void *ns_dyn_mem_temporary_alloc(ns_mem_block_size_t alloc_size);
|
extern void *ns_dyn_mem_temporary_alloc(ns_mem_block_size_t alloc_size);
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Allocate long period data.
|
* \brief Allocate long period data.
|
||||||
|
@ -123,7 +130,9 @@ extern void *ns_dyn_mem_temporary_alloc(ns_mem_block_size_t alloc_size);
|
||||||
* \return 0, Allocate Fail
|
* \return 0, Allocate Fail
|
||||||
* \return >0, Pointer to allocated data sector.
|
* \return >0, Pointer to allocated data sector.
|
||||||
*/
|
*/
|
||||||
|
#if NSDYNMEM_TRACKER_ENABLED!=1
|
||||||
extern void *ns_dyn_mem_alloc(ns_mem_block_size_t alloc_size);
|
extern void *ns_dyn_mem_alloc(ns_mem_block_size_t alloc_size);
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Get pointer to the current mem_stat_t set via ns_dyn_mem_init.
|
* \brief Get pointer to the current mem_stat_t set via ns_dyn_mem_init.
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 ARM Limited. All rights reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||||
|
* not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file nsdynmem_tracker.h
|
||||||
|
* \brief Dynamical Memory Tracker definitions to override the default NS dynamic memory functionality
|
||||||
|
* Provides tracking and tracing of dynamic memory blocks
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef NSDYNMEM_TRACKER_H_
|
||||||
|
#define NSDYNMEM_TRACKER_H_
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if NSDYNMEM_TRACKER_ENABLED==1
|
||||||
|
|
||||||
|
#define ns_dyn_mem_free(block) ns_dyn_mem_tracker_dyn_mem_free(block, __func__, __LINE__)
|
||||||
|
#define ns_dyn_mem_temporary_alloc(alloc_size) ns_dyn_mem_tracker_dyn_mem_temporary_alloc(alloc_size, __func__, __LINE__)
|
||||||
|
#define ns_dyn_mem_alloc(alloc_size) ns_dyn_mem_tracker_dyn_mem_alloc(alloc_size, __func__, __LINE__)
|
||||||
|
|
||||||
|
void *ns_dyn_mem_tracker_dyn_mem_alloc(ns_mem_heap_size_t alloc_size, const char *function, uint32_t line);
|
||||||
|
void *ns_dyn_mem_tracker_dyn_mem_temporary_alloc(ns_mem_heap_size_t alloc_size, const char *function, uint32_t line);
|
||||||
|
void ns_dyn_mem_tracker_dyn_mem_free(void *block, const char *function, uint32_t line);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif /* NSDYNMEM_TRACKER_H_ */
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,104 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 ARM Limited. All rights reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||||
|
* not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file nsdynmem_tracker_lib.h
|
||||||
|
* \brief Dynamical Memory Tracker library API
|
||||||
|
* Provides tracking and tracing of dynamic memory blocks
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef NSDYNMEM_TRACKER_LIB_H_
|
||||||
|
#define NSDYNMEM_TRACKER_LIB_H_
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if NSDYNMEM_TRACKER_ENABLED==1
|
||||||
|
|
||||||
|
// Memory block structure with caller information
|
||||||
|
typedef struct ns_dyn_mem_tracker_lib_mem_blocks_s {
|
||||||
|
void *block; /**< Allocated memory block */
|
||||||
|
void *caller_addr; /**< Caller address */
|
||||||
|
uint32_t size; /**< Allocation size */
|
||||||
|
uint32_t total_size; /**< Total allocation size for all allocations */
|
||||||
|
uint32_t lifetime; /**< Memory block lifetime in steps (e.g. seconds) */
|
||||||
|
uint32_t ref_count; /**< Reference count */
|
||||||
|
const char *function; /**< Caller function */
|
||||||
|
uint16_t line; /**< Caller line in module */
|
||||||
|
bool permanent : 1; /**< Permanent memory block */
|
||||||
|
bool permanent_printed : 1; /**< Permanent memory block printed */
|
||||||
|
} ns_dyn_mem_tracker_lib_mem_blocks_t;
|
||||||
|
|
||||||
|
// Extended memory block structure that is used if same caller allocates multiple memory blocks
|
||||||
|
typedef struct ns_dyn_mem_tracker_lib_mem_blocks_ext_s {
|
||||||
|
void *block; /**< Allocated memory block */
|
||||||
|
void *caller_addr; /**< Caller address */
|
||||||
|
uint32_t size; /**< Allocation size */
|
||||||
|
} ns_dyn_mem_tracker_lib_mem_blocks_ext_t;
|
||||||
|
|
||||||
|
// Allocator information structure
|
||||||
|
typedef struct ns_dyn_mem_tracker_lib_allocators_s {
|
||||||
|
void *caller_addr; /**< Caller address */
|
||||||
|
uint32_t alloc_count; /**< Number of allocations */
|
||||||
|
uint32_t total_memory; /**< Total memory used by allocations */
|
||||||
|
uint32_t min_lifetime; /**< Shortest lifetime among the allocations */
|
||||||
|
const char *function; /**< Function name string */
|
||||||
|
uint16_t line; /**< Module line */
|
||||||
|
} ns_dyn_mem_tracker_lib_allocators_t;
|
||||||
|
|
||||||
|
// Memory block array allocator / array size increase allocator
|
||||||
|
typedef ns_dyn_mem_tracker_lib_mem_blocks_t *ns_dyn_mem_tracker_lib_alloc_mem_blocks(ns_dyn_mem_tracker_lib_mem_blocks_t *blocks, uint16_t *mem_blocks_count);
|
||||||
|
// Extended memory block array allocator / array size increase allocator
|
||||||
|
typedef ns_dyn_mem_tracker_lib_mem_blocks_ext_t *ns_dyn_mem_tracker_lib_alloc_mem_blocks_ext(ns_dyn_mem_tracker_lib_mem_blocks_ext_t *blocks, uint32_t *mem_blocks_count);
|
||||||
|
// Extended memory block array index hash function to get memory block (allocation/search start) index from block address
|
||||||
|
typedef uint32_t ns_dyn_mem_tracker_lib_mem_block_index_hash(void *block, uint32_t ext_mem_blocks_count);
|
||||||
|
|
||||||
|
typedef struct ns_dyn_mem_tracker_lib_conf_s {
|
||||||
|
ns_dyn_mem_tracker_lib_mem_blocks_t *mem_blocks; /**< Memory blocks array, if NULL calls allocator on init */
|
||||||
|
ns_dyn_mem_tracker_lib_mem_blocks_ext_t *ext_mem_blocks; /**< Extended memory blocks array, if NULL calls allocator on init */
|
||||||
|
ns_dyn_mem_tracker_lib_allocators_t *top_allocators; /**< Top allocators array */
|
||||||
|
ns_dyn_mem_tracker_lib_allocators_t *permanent_allocators; /**< Permanent allocators */
|
||||||
|
ns_dyn_mem_tracker_lib_allocators_t *to_permanent_allocators; /**< To permanent allocators */
|
||||||
|
ns_dyn_mem_tracker_lib_allocators_t *max_snap_shot_allocators; /**< Snap shot of maximum memory used by allocators */
|
||||||
|
ns_dyn_mem_tracker_lib_alloc_mem_blocks *alloc_mem_blocks; /**< Memory block array allocator / array size increase allocator */
|
||||||
|
ns_dyn_mem_tracker_lib_alloc_mem_blocks_ext *ext_alloc_mem_blocks; /**< Extended memory block array allocator / array size increase allocator */
|
||||||
|
ns_dyn_mem_tracker_lib_mem_block_index_hash *block_index_hash; /**< Hash function to get memory block index from block address */
|
||||||
|
uint32_t allocated_memory; /**< Currently allocated memory */
|
||||||
|
uint16_t mem_blocks_count; /**< Number of entries in memory blocks array */
|
||||||
|
uint32_t ext_mem_blocks_count; /**< Number of entries in extended memory blocks array */
|
||||||
|
uint16_t last_mem_block_index; /**< Last memory block in memory blocks array */
|
||||||
|
uint16_t top_allocators_count; /**< Top allocators array count */
|
||||||
|
uint16_t permanent_allocators_count; /**< Permanent allocators array count */
|
||||||
|
uint16_t to_permanent_allocators_count; /**< To permanent allocators array count */
|
||||||
|
uint16_t max_snap_shot_allocators_count; /**< Snap shot of maximum memory used by allocators array count */
|
||||||
|
uint16_t to_permanent_steps_count; /**< How many steps before moving block to permanent allocators list */
|
||||||
|
} ns_dyn_mem_tracker_lib_conf_t;
|
||||||
|
|
||||||
|
int8_t ns_dyn_mem_tracker_lib_alloc(ns_dyn_mem_tracker_lib_conf_t *conf, void *caller_addr, const char *function, uint32_t line, void *block, uint32_t alloc_size);
|
||||||
|
int8_t ns_dyn_mem_tracker_lib_free(ns_dyn_mem_tracker_lib_conf_t *conf, void *caller_addr, const char *function, uint32_t line, void *block);
|
||||||
|
void ns_dyn_mem_tracker_lib_step(ns_dyn_mem_tracker_lib_conf_t *conf);
|
||||||
|
int8_t ns_dyn_mem_tracker_lib_allocator_lists_update(ns_dyn_mem_tracker_lib_conf_t *conf);
|
||||||
|
void ns_dyn_mem_tracker_lib_max_snap_shot_update(ns_dyn_mem_tracker_lib_conf_t *conf);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif /* NSDYNMEM_TRACKER_LIB_H_ */
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,10 @@
|
||||||
{
|
{
|
||||||
"name": "nanostack-libservice"
|
"name": "nanostack-libservice",
|
||||||
|
"macros": ["NSDYNMEM_TRACKER_ENABLED=MBED_CONF_NANOSTACK_LIBSERVICE_NSDYNMEM_TRACKER_ENABLED"],
|
||||||
|
"config": {
|
||||||
|
"nsdynmem-tracker-enabled": {
|
||||||
|
"help": "Use to enable dynamic memory tracker",
|
||||||
|
"value": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#undef NSDYNMEM_TRACKER_ENABLED
|
||||||
#include "nsdynmemLIB.h"
|
#include "nsdynmemLIB.h"
|
||||||
#include "platform/arm_hal_interrupt.h"
|
#include "platform/arm_hal_interrupt.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
|
@ -0,0 +1,480 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 ARM Limited. All rights reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||||
|
* not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "ns_types.h"
|
||||||
|
#include "nsdynmem_tracker_lib.h"
|
||||||
|
#include "platform/arm_hal_interrupt.h"
|
||||||
|
#include "nsdynmemLIB.h"
|
||||||
|
|
||||||
|
#if NSDYNMEM_TRACKER_ENABLED==1
|
||||||
|
|
||||||
|
static int8_t ns_dyn_mem_tracker_lib_find_free_index(ns_dyn_mem_tracker_lib_conf_t *conf, uint16_t *index);
|
||||||
|
static int8_t ns_dyn_mem_tracker_lib_find_caller_index(ns_dyn_mem_tracker_lib_conf_t *conf, void *caller_addr, uint16_t *caller_index);
|
||||||
|
static int8_t ns_dyn_mem_tracker_lib_find_block_index(ns_dyn_mem_tracker_lib_conf_t *conf, void *block, uint16_t *block_index);
|
||||||
|
static int8_t ns_dyn_mem_tracker_lib_ext_find_free_index(ns_dyn_mem_tracker_lib_conf_t *conf, uint32_t start_index, uint32_t *free_index);
|
||||||
|
static void ns_dyn_mem_tracker_lib_permanent_printed_value_set(ns_dyn_mem_tracker_lib_conf_t *conf, void *caller_addr, bool new_value);
|
||||||
|
static int8_t ns_dyn_mem_tracker_lib_ext_find_block_index(ns_dyn_mem_tracker_lib_conf_t *conf, void *block, uint32_t start_index, uint32_t *block_index);
|
||||||
|
|
||||||
|
int8_t ns_dyn_mem_tracker_lib_alloc(ns_dyn_mem_tracker_lib_conf_t *conf, void *caller_addr, const char *function, uint32_t line, void *block, uint32_t alloc_size)
|
||||||
|
{
|
||||||
|
// Allocation failed
|
||||||
|
if (block == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
platform_enter_critical();
|
||||||
|
|
||||||
|
// If dynamic memory blocks are not set, calls allocator
|
||||||
|
if (conf->mem_blocks == NULL) {
|
||||||
|
conf->mem_blocks = conf->alloc_mem_blocks(conf->mem_blocks, &conf->mem_blocks_count);
|
||||||
|
if (conf->mem_blocks == NULL) {
|
||||||
|
platform_exit_critical();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t caller_index = 0;
|
||||||
|
if (ns_dyn_mem_tracker_lib_find_caller_index(conf, caller_addr, &caller_index) >= 0) {
|
||||||
|
if (conf->ext_mem_blocks == NULL) {
|
||||||
|
conf->ext_mem_blocks = conf->ext_alloc_mem_blocks(conf->ext_mem_blocks, &conf->ext_mem_blocks_count);
|
||||||
|
if (conf->ext_mem_blocks == NULL) {
|
||||||
|
platform_exit_critical();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t free_index = 0;
|
||||||
|
uint32_t start_index = 0;
|
||||||
|
if (conf->block_index_hash != NULL) {
|
||||||
|
start_index = conf->block_index_hash(block, conf->ext_mem_blocks_count);
|
||||||
|
}
|
||||||
|
if (ns_dyn_mem_tracker_lib_ext_find_free_index(conf, start_index, &free_index) < 0) {
|
||||||
|
conf->ext_mem_blocks = conf->ext_alloc_mem_blocks(conf->ext_mem_blocks, &conf->ext_mem_blocks_count);
|
||||||
|
if (conf->ext_mem_blocks == NULL) {
|
||||||
|
platform_exit_critical();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (conf->block_index_hash != NULL) {
|
||||||
|
start_index = conf->block_index_hash(block, conf->ext_mem_blocks_count);
|
||||||
|
}
|
||||||
|
if (ns_dyn_mem_tracker_lib_ext_find_free_index(conf, start_index, &free_index) < 0) {
|
||||||
|
platform_exit_critical();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Updates memory blocks array entry
|
||||||
|
conf->mem_blocks[caller_index].ref_count++;
|
||||||
|
conf->mem_blocks[caller_index].total_size += alloc_size;
|
||||||
|
conf->mem_blocks[caller_index].lifetime = 0;
|
||||||
|
conf->mem_blocks[caller_index].permanent = false;
|
||||||
|
conf->mem_blocks[caller_index].permanent_printed = false;
|
||||||
|
|
||||||
|
conf->ext_mem_blocks[free_index].block = block;
|
||||||
|
conf->ext_mem_blocks[free_index].caller_addr = caller_addr;
|
||||||
|
conf->ext_mem_blocks[free_index].size = alloc_size;
|
||||||
|
|
||||||
|
conf->allocated_memory += alloc_size;
|
||||||
|
|
||||||
|
platform_exit_critical();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t free_index = 0;
|
||||||
|
if (ns_dyn_mem_tracker_lib_find_free_index(conf, &free_index) < 0) {
|
||||||
|
conf->mem_blocks = conf->alloc_mem_blocks(conf->mem_blocks, &conf->mem_blocks_count);
|
||||||
|
if (conf->mem_blocks == NULL || (ns_dyn_mem_tracker_lib_find_free_index(conf, &free_index) < 0)) {
|
||||||
|
platform_exit_critical();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
conf->mem_blocks[free_index].block = block;
|
||||||
|
conf->mem_blocks[free_index].caller_addr = caller_addr;
|
||||||
|
conf->mem_blocks[free_index].size = alloc_size;
|
||||||
|
conf->mem_blocks[free_index].total_size = alloc_size;
|
||||||
|
conf->mem_blocks[free_index].lifetime = 0;
|
||||||
|
conf->mem_blocks[free_index].ref_count = 1;
|
||||||
|
conf->mem_blocks[free_index].function = function;
|
||||||
|
conf->mem_blocks[free_index].line = line;
|
||||||
|
conf->mem_blocks[free_index].permanent = false;
|
||||||
|
conf->mem_blocks[free_index].permanent_printed = false;
|
||||||
|
|
||||||
|
if (free_index > conf->last_mem_block_index) {
|
||||||
|
conf->last_mem_block_index = free_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
conf->allocated_memory += alloc_size;
|
||||||
|
|
||||||
|
platform_exit_critical();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t ns_dyn_mem_tracker_lib_free(ns_dyn_mem_tracker_lib_conf_t *conf, void *caller_addr, const char *function, uint32_t line, void *block)
|
||||||
|
{
|
||||||
|
(void) function;
|
||||||
|
(void) line;
|
||||||
|
(void) caller_addr;
|
||||||
|
|
||||||
|
// No memory block or no allocations made
|
||||||
|
if (block == NULL || conf->mem_blocks == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
platform_enter_critical();
|
||||||
|
|
||||||
|
uint16_t block_index = 0;
|
||||||
|
if (ns_dyn_mem_tracker_lib_find_block_index(conf, block, &block_index) >= 0) {
|
||||||
|
// If last block for allocator clears the allocator
|
||||||
|
if (conf->mem_blocks[block_index].ref_count <= 1) {
|
||||||
|
conf->mem_blocks[block_index].ref_count = 0;
|
||||||
|
conf->mem_blocks[block_index].caller_addr = NULL;
|
||||||
|
conf->mem_blocks[block_index].total_size = 0;
|
||||||
|
conf->mem_blocks[block_index].function = NULL;
|
||||||
|
conf->mem_blocks[block_index].line = 0;
|
||||||
|
} else {
|
||||||
|
// Other blocks exists
|
||||||
|
conf->mem_blocks[block_index].ref_count--;
|
||||||
|
conf->mem_blocks[block_index].total_size -= conf->mem_blocks[block_index].size;
|
||||||
|
}
|
||||||
|
|
||||||
|
conf->allocated_memory -= conf->mem_blocks[block_index].size;
|
||||||
|
|
||||||
|
// Clears block specific fields
|
||||||
|
conf->mem_blocks[block_index].block = NULL;
|
||||||
|
conf->mem_blocks[block_index].size = 0;
|
||||||
|
// Resets lifetime and permanent settings
|
||||||
|
conf->mem_blocks[block_index].lifetime = 0;
|
||||||
|
conf->mem_blocks[block_index].permanent = false;
|
||||||
|
conf->mem_blocks[block_index].permanent_printed = false;
|
||||||
|
|
||||||
|
platform_exit_critical();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conf->ext_mem_blocks == NULL) {
|
||||||
|
platform_exit_critical();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t ext_block_index = 0;
|
||||||
|
uint32_t start_index = 0;
|
||||||
|
if (conf->block_index_hash != NULL) {
|
||||||
|
start_index = conf->block_index_hash(block, conf->ext_mem_blocks_count);
|
||||||
|
}
|
||||||
|
if (ns_dyn_mem_tracker_lib_ext_find_block_index(conf, block, start_index, &ext_block_index) < 0) {
|
||||||
|
platform_exit_critical();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *ext_caller_addr = conf->ext_mem_blocks[ext_block_index].caller_addr;
|
||||||
|
|
||||||
|
uint16_t caller_index;
|
||||||
|
if (ns_dyn_mem_tracker_lib_find_caller_index(conf, ext_caller_addr, &caller_index) < 0) {
|
||||||
|
platform_exit_critical();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
conf->mem_blocks[caller_index].ref_count--;
|
||||||
|
conf->mem_blocks[caller_index].total_size -= conf->ext_mem_blocks[ext_block_index].size;
|
||||||
|
|
||||||
|
conf->allocated_memory -= conf->ext_mem_blocks[ext_block_index].size;
|
||||||
|
|
||||||
|
// Clears extended block
|
||||||
|
conf->ext_mem_blocks[ext_block_index].block = NULL;
|
||||||
|
conf->ext_mem_blocks[ext_block_index].caller_addr = NULL;
|
||||||
|
conf->ext_mem_blocks[ext_block_index].size = 0;
|
||||||
|
|
||||||
|
// Resets lifetime and permanent settings
|
||||||
|
conf->mem_blocks[block_index].lifetime = 0;
|
||||||
|
conf->mem_blocks[block_index].permanent = false;
|
||||||
|
conf->mem_blocks[block_index].permanent_printed = false;
|
||||||
|
|
||||||
|
// If last block for allocator clears the allocator
|
||||||
|
if (conf->mem_blocks[block_index].ref_count == 0) {
|
||||||
|
conf->mem_blocks[block_index].block = NULL;
|
||||||
|
conf->mem_blocks[block_index].caller_addr = NULL;
|
||||||
|
conf->mem_blocks[block_index].size = 0;
|
||||||
|
conf->mem_blocks[block_index].total_size = 0;
|
||||||
|
conf->mem_blocks[block_index].function = NULL;
|
||||||
|
conf->mem_blocks[block_index].line = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
platform_exit_critical();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ns_dyn_mem_tracker_lib_step(ns_dyn_mem_tracker_lib_conf_t *conf)
|
||||||
|
{
|
||||||
|
platform_enter_critical();
|
||||||
|
|
||||||
|
if (conf->mem_blocks_count != 0) {
|
||||||
|
for (uint32_t index = 0; index <= conf->last_mem_block_index; index++) {
|
||||||
|
if (conf->mem_blocks[index].block != NULL) {
|
||||||
|
conf->mem_blocks[index].lifetime++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
platform_exit_critical();
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t ns_dyn_mem_tracker_lib_allocator_lists_update(ns_dyn_mem_tracker_lib_conf_t *conf)
|
||||||
|
{
|
||||||
|
platform_enter_critical();
|
||||||
|
|
||||||
|
ns_dyn_mem_tracker_lib_mem_blocks_t *blocks = conf->mem_blocks;
|
||||||
|
ns_dyn_mem_tracker_lib_allocators_t *top_allocators = conf->top_allocators;
|
||||||
|
ns_dyn_mem_tracker_lib_allocators_t *permanent_allocators = conf->permanent_allocators;
|
||||||
|
ns_dyn_mem_tracker_lib_allocators_t *to_permanent_allocators = conf->to_permanent_allocators;
|
||||||
|
|
||||||
|
uint16_t top_allocators_count = conf->top_allocators_count;
|
||||||
|
uint16_t permanent_allocators_count = conf->permanent_allocators_count;
|
||||||
|
uint16_t to_permanent_allocators_count = conf->to_permanent_allocators_count;
|
||||||
|
|
||||||
|
memset(top_allocators, 0, top_allocators_count * sizeof(ns_dyn_mem_tracker_lib_allocators_t));
|
||||||
|
memset(permanent_allocators, 0, permanent_allocators_count * sizeof(ns_dyn_mem_tracker_lib_allocators_t));
|
||||||
|
memset(to_permanent_allocators, 0, to_permanent_allocators_count * sizeof(ns_dyn_mem_tracker_lib_allocators_t));
|
||||||
|
|
||||||
|
// Maximum set as permanent in one go
|
||||||
|
uint8_t to_permanent_count = 0;
|
||||||
|
|
||||||
|
// Maximum to print of permanent entries
|
||||||
|
uint8_t permanent_count = 0;
|
||||||
|
|
||||||
|
for (uint32_t index = 0; index <= conf->last_mem_block_index; index++) {
|
||||||
|
if (blocks[index].block != NULL) {
|
||||||
|
void *caller_addr = blocks[index].caller_addr;
|
||||||
|
|
||||||
|
// Checks if caller address has already been counted
|
||||||
|
bool next = false;
|
||||||
|
for (uint32_t list_index = 0; list_index < top_allocators_count; list_index++) {
|
||||||
|
if (top_allocators[list_index].caller_addr == caller_addr) {
|
||||||
|
next = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (next) {
|
||||||
|
// Already on list, continue
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks whether all reference are marked permanent
|
||||||
|
if (blocks[index].permanent) {
|
||||||
|
if (!blocks[index].permanent_printed && permanent_count < permanent_allocators_count) {
|
||||||
|
permanent_allocators[permanent_count].caller_addr = caller_addr;
|
||||||
|
permanent_allocators[permanent_count].alloc_count = blocks[index].ref_count;
|
||||||
|
permanent_allocators[permanent_count].total_memory = blocks[index].total_size;
|
||||||
|
permanent_allocators[permanent_count].min_lifetime = blocks[index].lifetime;
|
||||||
|
permanent_allocators[permanent_count].function = blocks[index].function;
|
||||||
|
permanent_allocators[permanent_count].line = blocks[index].line;
|
||||||
|
|
||||||
|
permanent_count++;
|
||||||
|
blocks[index].permanent_printed = true;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
// Checks whether lifetime threshold has been reached, traces and skips
|
||||||
|
if (blocks[index].lifetime > conf->to_permanent_steps_count && to_permanent_count < to_permanent_allocators_count) {
|
||||||
|
blocks[index].permanent = true;
|
||||||
|
|
||||||
|
to_permanent_allocators[to_permanent_count].caller_addr = caller_addr;
|
||||||
|
to_permanent_allocators[to_permanent_count].alloc_count = blocks[index].ref_count;
|
||||||
|
to_permanent_allocators[to_permanent_count].total_memory = blocks[index].total_size;
|
||||||
|
to_permanent_allocators[to_permanent_count].min_lifetime = blocks[index].lifetime;
|
||||||
|
to_permanent_allocators[to_permanent_count].function = blocks[index].function;
|
||||||
|
to_permanent_allocators[to_permanent_count].line = blocks[index].line;
|
||||||
|
|
||||||
|
to_permanent_count++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add to list if allocation count is larger than entry on the list
|
||||||
|
for (uint16_t list_index = 0; list_index < top_allocators_count; list_index++) {
|
||||||
|
if (blocks[index].ref_count >= top_allocators[list_index].alloc_count) {
|
||||||
|
if (list_index != (top_allocators_count - 1)) {
|
||||||
|
uint8_t index_count = (top_allocators_count - list_index - 1);
|
||||||
|
uint32_t size = index_count * sizeof(ns_dyn_mem_tracker_lib_allocators_t);
|
||||||
|
memmove(&top_allocators[list_index + 1], &top_allocators[list_index], size);
|
||||||
|
}
|
||||||
|
top_allocators[list_index].caller_addr = caller_addr;
|
||||||
|
top_allocators[list_index].alloc_count = blocks[index].ref_count;
|
||||||
|
top_allocators[list_index].total_memory = blocks[index].total_size;
|
||||||
|
top_allocators[list_index].min_lifetime = blocks[index].lifetime;
|
||||||
|
top_allocators[list_index].function = blocks[index].function;
|
||||||
|
top_allocators[list_index].line = blocks[index].line;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (permanent_count < permanent_allocators_count) {
|
||||||
|
ns_dyn_mem_tracker_lib_permanent_printed_value_set(conf, NULL, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
platform_exit_critical();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ns_dyn_mem_tracker_lib_max_snap_shot_update(ns_dyn_mem_tracker_lib_conf_t *conf)
|
||||||
|
{
|
||||||
|
platform_enter_critical();
|
||||||
|
|
||||||
|
ns_dyn_mem_tracker_lib_mem_blocks_t *blocks = conf->mem_blocks;
|
||||||
|
ns_dyn_mem_tracker_lib_allocators_t *max_snap_shot_allocators = conf->max_snap_shot_allocators;
|
||||||
|
|
||||||
|
uint16_t max_snap_shot_allocators_count = conf->max_snap_shot_allocators_count;
|
||||||
|
|
||||||
|
memset(max_snap_shot_allocators, 0, max_snap_shot_allocators_count * sizeof(ns_dyn_mem_tracker_lib_allocators_t));
|
||||||
|
|
||||||
|
for (uint32_t index = 0; index <= conf->last_mem_block_index; index++) {
|
||||||
|
if (blocks[index].block != NULL) {
|
||||||
|
void *caller_addr = blocks[index].caller_addr;
|
||||||
|
|
||||||
|
// Checks if caller address has already been counted
|
||||||
|
bool next = false;
|
||||||
|
for (uint16_t list_index = 0; list_index < max_snap_shot_allocators_count; list_index++) {
|
||||||
|
if (max_snap_shot_allocators[list_index].caller_addr == caller_addr) {
|
||||||
|
next = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (next) {
|
||||||
|
// Already on list, continue
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add to list if allocation count is larger than entry on the list
|
||||||
|
for (uint16_t list_index = 0; list_index < max_snap_shot_allocators_count; list_index++) {
|
||||||
|
if (blocks[index].total_size >= max_snap_shot_allocators[list_index].total_memory) {
|
||||||
|
if (list_index != (max_snap_shot_allocators_count - 1)) {
|
||||||
|
uint8_t index_count = (max_snap_shot_allocators_count - list_index - 1);
|
||||||
|
uint32_t size = index_count * sizeof(ns_dyn_mem_tracker_lib_allocators_t);
|
||||||
|
memmove(&max_snap_shot_allocators[list_index + 1], &max_snap_shot_allocators[list_index], size);
|
||||||
|
}
|
||||||
|
max_snap_shot_allocators[list_index].caller_addr = blocks[index].caller_addr;
|
||||||
|
max_snap_shot_allocators[list_index].alloc_count = blocks[index].ref_count;
|
||||||
|
max_snap_shot_allocators[list_index].total_memory = blocks[index].total_size;
|
||||||
|
max_snap_shot_allocators[list_index].min_lifetime = blocks[index].lifetime;
|
||||||
|
max_snap_shot_allocators[list_index].function = blocks[index].function;
|
||||||
|
max_snap_shot_allocators[list_index].line = blocks[index].line;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
platform_exit_critical();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ns_dyn_mem_tracker_lib_permanent_printed_value_set(ns_dyn_mem_tracker_lib_conf_t *conf, void *caller_addr, bool new_value)
|
||||||
|
{
|
||||||
|
/* Search for all the references to the caller address from the allocation info and
|
||||||
|
set block permanent value */
|
||||||
|
for (uint16_t search_index = 0; search_index <= conf->last_mem_block_index; search_index++) {
|
||||||
|
if (caller_addr == NULL || conf->mem_blocks[search_index].caller_addr == caller_addr) {
|
||||||
|
conf->mem_blocks[search_index].permanent_printed = new_value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int8_t ns_dyn_mem_tracker_lib_find_free_index(ns_dyn_mem_tracker_lib_conf_t *conf, uint16_t *free_index)
|
||||||
|
{
|
||||||
|
for (uint16_t index = 0; index < conf->mem_blocks_count; index++) {
|
||||||
|
if (conf->mem_blocks[index].caller_addr == NULL) {
|
||||||
|
*free_index = index;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int8_t ns_dyn_mem_tracker_lib_find_caller_index(ns_dyn_mem_tracker_lib_conf_t *conf, void *caller_addr, uint16_t *caller_index)
|
||||||
|
{
|
||||||
|
for (uint16_t index = 0; index <= conf->last_mem_block_index; index++) {
|
||||||
|
if (conf->mem_blocks[index].caller_addr == caller_addr) {
|
||||||
|
*caller_index = index;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int8_t ns_dyn_mem_tracker_lib_find_block_index(ns_dyn_mem_tracker_lib_conf_t *conf, void *block, uint16_t *block_index)
|
||||||
|
{
|
||||||
|
for (uint16_t index = 0; index <= conf->last_mem_block_index; index++) {
|
||||||
|
if (conf->mem_blocks[index].block == block) {
|
||||||
|
*block_index = index;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int8_t ns_dyn_mem_tracker_lib_ext_find_free_index(ns_dyn_mem_tracker_lib_conf_t *conf, uint32_t start_index, uint32_t *free_index)
|
||||||
|
{
|
||||||
|
for (uint32_t index = start_index; index < conf->ext_mem_blocks_count; index++) {
|
||||||
|
if (conf->ext_mem_blocks[index].caller_addr == NULL) {
|
||||||
|
*free_index = index;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (start_index == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t index = 0; index < start_index; index++) {
|
||||||
|
if (conf->ext_mem_blocks[index].caller_addr == NULL) {
|
||||||
|
*free_index = index;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int8_t ns_dyn_mem_tracker_lib_ext_find_block_index(ns_dyn_mem_tracker_lib_conf_t *conf, void *block, uint32_t start_index, uint32_t *block_index)
|
||||||
|
{
|
||||||
|
for (uint32_t index = start_index; index < conf->ext_mem_blocks_count; index++) {
|
||||||
|
if (conf->ext_mem_blocks[index].block == block) {
|
||||||
|
*block_index = index;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (start_index == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t index = 0; index < start_index; index++) {
|
||||||
|
if (conf->ext_mem_blocks[index].block == block) {
|
||||||
|
*block_index = index;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue