mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-09 04:25:32 +00:00
docs(heap_debug): Add missing information
- Place the section on alloc failed hook at a better place - Add reference to the different poisoning configs at the beginning of the heap corruption detectino section - Update the information concerning heap tracing - Update the heap tracing log examples - Fix heap tracing standalone code: - Update the logging format in heap_trace_dump_base - Add freed field in trace stucture to keep this info even when no call stack is available
This commit is contained in:
@@ -43,6 +43,37 @@ menu "Heap memory debugging"
|
||||
help
|
||||
Enables/disables heap tracing API.
|
||||
|
||||
config HEAP_TRACE_HASH_MAP
|
||||
bool "Use hash map mechanism to access heap trace records"
|
||||
depends on HEAP_TRACING_STANDALONE
|
||||
default n
|
||||
help
|
||||
Enable this flag to use a hash map to increase performance in handling
|
||||
heap trace records.
|
||||
|
||||
Heap trace standalone supports storing records as a list, or a list + hash map.
|
||||
|
||||
Using only a list takes less memory, but calls to 'free' will get slower as the
|
||||
list grows. This is particularly affected when using HEAP_TRACE_ALL mode.
|
||||
|
||||
By using a list + hash map, calls to 'free' remain fast, at the cost of
|
||||
additional memory to store the hash map.
|
||||
|
||||
config HEAP_TRACE_HASH_MAP_IN_EXT_RAM
|
||||
bool "Place hash map in external RAM"
|
||||
depends on SPIRAM && HEAP_TRACE_HASH_MAP
|
||||
default n
|
||||
help
|
||||
When enabled this configuration forces the hash map to be placed in external RAM.
|
||||
|
||||
config HEAP_TRACE_HASH_MAP_SIZE
|
||||
int "The number of entries in the hash map"
|
||||
depends on HEAP_TRACE_HASH_MAP
|
||||
default 512
|
||||
help
|
||||
Defines the number of entries in the heap trace hashmap. Each entry takes 8 bytes.
|
||||
The bigger this number is, the better the performance. Recommended range: 200 - 2000.
|
||||
|
||||
config HEAP_TRACING_STACK_DEPTH
|
||||
int "Heap tracing stack depth"
|
||||
range 0 0 if IDF_TARGET_ARCH_RISCV # Disabled for RISC-V due to `__builtin_return_address` limitation
|
||||
@@ -69,37 +100,6 @@ menu "Heap memory debugging"
|
||||
This function depends on heap poisoning being enabled and adds four more bytes of overhead for each block
|
||||
allocated.
|
||||
|
||||
config HEAP_TRACE_HASH_MAP
|
||||
bool "Use hash map mechanism to access heap trace records"
|
||||
depends on HEAP_TRACING_STANDALONE
|
||||
default n
|
||||
help
|
||||
Enable this flag to use a hash map to increase performance in handling
|
||||
heap trace records.
|
||||
|
||||
Heap trace standalone supports storing records as a list, or a list + hash map.
|
||||
|
||||
Using only a list takes less memory, but calls to 'free' will get slower as the
|
||||
list grows. This is particularly affected when using HEAP_TRACE_ALL mode.
|
||||
|
||||
By using a list + hash map, calls to 'free' remain fast, at the cost of
|
||||
additional memory to store the hash map.
|
||||
|
||||
config HEAP_TRACE_HASH_MAP_IN_EXT_RAM
|
||||
bool "Place hash map in external RAM"
|
||||
depends on HEAP_TRACE_HASH_MAP
|
||||
default n
|
||||
help
|
||||
When enabled this configuration forces the hash map to be placed in external RAM.
|
||||
|
||||
config HEAP_TRACE_HASH_MAP_SIZE
|
||||
int "The number of entries in the hash map"
|
||||
depends on HEAP_TRACE_HASH_MAP
|
||||
default 512
|
||||
help
|
||||
Defines the number of entries in the heap trace hashmap. Each entry takes 8 bytes.
|
||||
The bigger this number is, the better the performance. Recommended range: 200 - 2000.
|
||||
|
||||
config HEAP_ABORT_WHEN_ALLOCATION_FAILS
|
||||
bool "Abort if memory allocation fails"
|
||||
default n
|
||||
|
@@ -380,24 +380,31 @@ static void heap_trace_dump_base(bool internal_ram, bool psram)
|
||||
label = ", PSRAM";
|
||||
}
|
||||
|
||||
esp_rom_printf("%6d bytes (@ %p%s) allocated CPU %d ccount 0x%08x caller ",
|
||||
esp_rom_printf("%6d bytes (@ %p%s) allocated CPU %d ccount 0x%08x",
|
||||
r_cur->size, r_cur->address, label, r_cur->ccount & 1, r_cur->ccount & ~3);
|
||||
|
||||
for (int j = 0; j < STACK_DEPTH && r_cur->alloced_by[j] != 0; j++) {
|
||||
esp_rom_printf("%p%s", r_cur->alloced_by[j],
|
||||
(j < STACK_DEPTH - 1) ? ":" : "");
|
||||
if (STACK_DEPTH != 0 && r_cur->alloced_by[0] != NULL) {
|
||||
esp_rom_printf(" caller ");
|
||||
for (int j = 0; j < STACK_DEPTH && r_cur->alloced_by[j] != 0; j++) {
|
||||
esp_rom_printf("%p%s", r_cur->alloced_by[j],
|
||||
(j < STACK_DEPTH - 1) ? ":" : "");
|
||||
}
|
||||
}
|
||||
|
||||
if (mode != HEAP_TRACE_ALL || STACK_DEPTH == 0 || r_cur->freed_by[0] == NULL) {
|
||||
if (r_cur->freed == true) {
|
||||
if ((mode == HEAP_TRACE_ALL) && (STACK_DEPTH != 0) && (r_cur->freed_by[0] != NULL)) {
|
||||
esp_rom_printf("\nfreed by ");
|
||||
for (int j = 0; j < STACK_DEPTH; j++) {
|
||||
esp_rom_printf("%p%s", r_cur->freed_by[j],
|
||||
(j < STACK_DEPTH - 1) ? ":" : "\n");
|
||||
}
|
||||
} else {
|
||||
esp_rom_printf(" freed\n");
|
||||
}
|
||||
} else {
|
||||
delta_size += r_cur->size;
|
||||
delta_allocs++;
|
||||
esp_rom_printf("\n");
|
||||
} else {
|
||||
esp_rom_printf("\nfreed by ");
|
||||
for (int j = 0; j < STACK_DEPTH; j++) {
|
||||
esp_rom_printf("%p%s", r_cur->freed_by[j],
|
||||
(j < STACK_DEPTH - 1) ? ":" : "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -500,6 +507,7 @@ static HEAP_IRAM_ATTR void record_free(void *p, void **callers)
|
||||
heap_trace_record_t *r_found = list_find(p);
|
||||
if (r_found != NULL) {
|
||||
// add 'freed_by' info to the record
|
||||
r_found->freed = true;
|
||||
memcpy(r_found->freed_by, callers, sizeof(void *) * STACK_DEPTH);
|
||||
}
|
||||
} else { // HEAP_TRACE_LEAKS
|
||||
@@ -538,6 +546,7 @@ static HEAP_IRAM_ATTR void list_remove(heap_trace_record_t* r_remove)
|
||||
// set as unused
|
||||
r_remove->address = 0;
|
||||
r_remove->size = 0;
|
||||
r_remove->freed = false;
|
||||
|
||||
// add to records.unused
|
||||
TAILQ_INSERT_HEAD(&records.unused, r_remove, tailq_list);
|
||||
@@ -559,6 +568,7 @@ static HEAP_IRAM_ATTR heap_trace_record_t* list_pop_unused(void)
|
||||
heap_trace_record_t *r_unused = TAILQ_FIRST(&records.unused);
|
||||
assert(r_unused->address == NULL);
|
||||
assert(r_unused->size == 0);
|
||||
assert(r_unused->freed == false);
|
||||
|
||||
// remove from records.unused
|
||||
TAILQ_REMOVE(&records.unused, r_unused, tailq_list);
|
||||
@@ -573,6 +583,7 @@ static HEAP_IRAM_ATTR void record_deep_copy(heap_trace_record_t *r_dest, const h
|
||||
r_dest->ccount = r_src->ccount;
|
||||
r_dest->address = r_src->address;
|
||||
r_dest->size = r_src->size;
|
||||
r_dest->freed = r_src->freed;
|
||||
memcpy(r_dest->freed_by, r_src->freed_by, sizeof(void *) * STACK_DEPTH);
|
||||
memcpy(r_dest->alloced_by, r_src->alloced_by, sizeof(void *) * STACK_DEPTH);
|
||||
}
|
||||
|
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "sys/queue.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <esp_err.h>
|
||||
|
||||
@@ -34,6 +35,7 @@ typedef struct heap_trace_record_t {
|
||||
uint32_t ccount; ///< CCOUNT of the CPU when the allocation was made. LSB (bit value 1) is the CPU number (0 or 1).
|
||||
void *address; ///< Address which was allocated. If NULL, then this record is empty.
|
||||
size_t size; ///< Size of the allocation
|
||||
bool freed; ///< State of the allocation (false if not freed, true if freed)
|
||||
void *alloced_by[CONFIG_HEAP_TRACING_STACK_DEPTH]; ///< Call stack of the caller which allocated the memory.
|
||||
void *freed_by[CONFIG_HEAP_TRACING_STACK_DEPTH]; ///< Call stack of the caller which freed the memory (all zero if not freed.)
|
||||
#if CONFIG_HEAP_TRACING_STANDALONE
|
||||
|
@@ -122,6 +122,7 @@ static HEAP_IRAM_ATTR __attribute__((noinline)) void *trace_malloc(size_t alignm
|
||||
.address = p,
|
||||
.ccount = ccount,
|
||||
.size = size,
|
||||
.freed = false,
|
||||
};
|
||||
get_call_stack(rec.alloced_by);
|
||||
record_allocation(&rec);
|
||||
|
@@ -42,8 +42,6 @@ TEST_CASE("heap trace leak check", "[heap-trace]")
|
||||
void *b = malloc(96);
|
||||
memset(b, '4', 11);
|
||||
|
||||
printf("a.address %p vs %p b.address %p vs %p\n", a, recs[0].address, b, recs[1].address);
|
||||
|
||||
heap_trace_dump();
|
||||
TEST_ASSERT_EQUAL(2, heap_trace_get_count());
|
||||
|
||||
@@ -51,8 +49,6 @@ TEST_CASE("heap trace leak check", "[heap-trace]")
|
||||
heap_trace_get(0, &trace_a);
|
||||
heap_trace_get(1, &trace_b);
|
||||
|
||||
printf("trace_a.address %p trace_bb.address %p\n", trace_a.address, trace_b.address);
|
||||
|
||||
TEST_ASSERT_EQUAL_PTR(a, trace_a.address);
|
||||
TEST_ASSERT_EQUAL_PTR(b, trace_b.address);
|
||||
|
||||
|
Reference in New Issue
Block a user