diff --git a/components/heap/esp_heap_debug.c b/components/heap/esp_heap_debug.c new file mode 100644 index 000000000..3fd9373ee --- /dev/null +++ b/components/heap/esp_heap_debug.c @@ -0,0 +1,102 @@ +#include +#include +#include +#include "multi_heap_internal.h" +//#include "multi_heap_poisoning.h" +#include "heap_private.h" +#include "esp_heap_debug.h" + +#ifdef CONFIG_HEAP_TASK_TRACKING + +// return all possible capabilities (across all priorities) for a given heap + +inline static uint32_t get_all_caps(const heap_t *heap) +{ + uint32_t all_caps = 0; + for (int prio = 0; prio < SOC_MEMORY_TYPE_NO_PRIOS; prio++) { + all_caps |= heap->caps[prio]; + } + return all_caps; +} + +// For each task that has allocated memory from the heap, return totals for +// allocations of each type of heap region (8-bit DRAM, 8-bit D/IRAM, 32-bit +// IRAM, SPIRAM) into provided array of heap_dump_totals_t structs 'totals'. + +// If one or more task handles is provided in array 'tasks', for each block +// allocated by one of the tasks a heap_dump_block_t struct is written into +// provided array 'buffer' to give the task, address, size and region type for +// the block. + +size_t esp_heap_debug_dump_totals(heap_dump_totals_t* totals, size_t* ntotal, size_t max, + TaskHandle_t* tasks, size_t ntasks, + heap_dump_block_t* buffer, size_t size) +{ + heap_t *reg; + size_t count = *ntotal; + size_t remaining = size; + size_t i; + + SLIST_FOREACH(reg, ®istered_heaps, next) { + multi_heap_handle_t heap = reg->heap; + if (heap == NULL) { + continue; + } + uint32_t caps = get_all_caps(reg); + enum region_types type = DRAM; + if (caps & MALLOC_CAP_EXEC) + type = D_IRAM; + if (!(caps & MALLOC_CAP_8BIT)) + type = IRAM; + if (caps & MALLOC_CAP_SPIRAM) + type = SPIRAM; + multi_heap_block_handle_t b = multi_heap_get_first_block(heap); + multi_heap_internal_lock(heap); + while (b) { + if (multi_heap_is_free(b)) { + b = multi_heap_get_next_block(heap, b); + continue; + } + void* p = multi_heap_get_block_address(b); // Safe, only arithmetic + size_t bsize = multi_heap_get_allocated_size(heap, p); // Validates + TaskHandle_t btask = (TaskHandle_t)multi_heap_get_block_owner(b); + size_t index; + for (index = 0; index < count; ++index) { + if (totals[index].task == btask) + break; + } + if (index < count) + totals[index].size[type] += bsize; + else { + if (count < max) { + totals[count].task = btask; + totals[count].size[type] = bsize; + ++count; + } + } + if (tasks) { + for (i = 0; i < ntasks; ++i) { + if (btask == tasks[i]) + break; + } + if (i == ntasks) { + b = multi_heap_get_next_block(heap, b); + continue; + } + } + if (remaining > 0) { + buffer->task = btask; + buffer->address = p; + buffer->size = bsize; + buffer->type = type; + ++buffer; + --remaining; + } + b = multi_heap_get_next_block(heap, b); + } + multi_heap_internal_unlock(heap); + } + *ntotal = count; + return size - remaining; +} +#endif diff --git a/components/heap/include/esp_heap_debug.h b/components/heap/include/esp_heap_debug.h new file mode 100644 index 000000000..3dde09d5b --- /dev/null +++ b/components/heap/include/esp_heap_debug.h @@ -0,0 +1,39 @@ +#ifndef _ESP_HEAP_DEBUG_H +#define _ESP_HEAP_DEBUG_H + +#ifdef CONFIG_HEAP_TASK_TRACKING + +#ifdef __cplusplus +extern "C" { +#endif + +enum region_types { + DRAM = 0, + D_IRAM = 1, + IRAM = 2, + SPIRAM = 3, + NUM_USED_TYPES = 4 +}; + +typedef struct { + TaskHandle_t task; + int size[NUM_USED_TYPES]; +} heap_dump_totals_t; + +typedef struct { + TaskHandle_t task; + void* address; + int size: 24; // The size of the allocated block. + int type: 7; // Type of block's region + int unused: 1; // (forces 32-bit access for type) +} heap_dump_block_t; + +extern size_t esp_heap_debug_dump_totals(heap_dump_totals_t* totals, size_t* ntotal, size_t max, + TaskHandle_t* tasks, size_t ntasks, + heap_dump_block_t* buffer, size_t size); +#ifdef __cplusplus +} +#endif + +#endif +#endif // _ESP_HEAP_DEBUG_H