Revise memory diagnostics to use task handle not task name
In addition, aggregation of the sizes of blocks allocated by each task to get a total is now done in new mem_debug_malloc_dump_totals() so it is not necessary to dump info for each individual heap block into an array for the app code. Only the blocks belonging to specific tasks will be dumped when those tasks are selected by the user for a detailed list of blocks. This change in the memory diagnostic API is indicated by a change in the conditional configENABLE_MEMORY_DEBUG_DUMP from 1 to 2.
This commit is contained in:
parent
88ab5d4830
commit
eb9f77247a
3 changed files with 97 additions and 36 deletions
|
@ -1,6 +1,6 @@
|
||||||
#include "heap_regions_debug.h"
|
|
||||||
#include "FreeRTOS.h"
|
#include "FreeRTOS.h"
|
||||||
#include "task.h"
|
#include "task.h"
|
||||||
|
#include "heap_regions_debug.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -33,9 +33,9 @@ void mem_debug_push(char type, void *addr)
|
||||||
MEM_DEBUG("push type=%d addr=%p\n", type, addr);
|
MEM_DEBUG("push type=%d addr=%p\n", type, addr);
|
||||||
if (g_mem_print){
|
if (g_mem_print){
|
||||||
if (type == DEBUG_TYPE_MALLOC){
|
if (type == DEBUG_TYPE_MALLOC){
|
||||||
ets_printf("task=%s t=%s s=%u a=%p\n", debug_b->head.task?debug_b->head.task:"", type==DEBUG_TYPE_MALLOC?"m":"f", b->size, addr);
|
ets_printf("task=%08X t=%s s=%u a=%p\n", debug_b->head.task, type==DEBUG_TYPE_MALLOC?"m":"f", b->size, addr);
|
||||||
} else {
|
} else {
|
||||||
ets_printf("task=%s t=%s s=%u a=%p\n", debug_b->head.task?debug_b->head.task:"", type==DEBUG_TYPE_MALLOC?"m":"f", b->size, addr);
|
ets_printf("task=%08X t=%s s=%u a=%p\n", debug_b->head.task, type==DEBUG_TYPE_MALLOC?"m":"f", b->size, addr);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mem_dbg_info_t *info = &g_mem_dbg.info[g_mem_dbg.cnt%DEBUG_MAX_INFO_NUM];
|
mem_dbg_info_t *info = &g_mem_dbg.info[g_mem_dbg.cnt%DEBUG_MAX_INFO_NUM];
|
||||||
|
@ -55,25 +55,24 @@ void mem_debug_malloc_show(void)
|
||||||
taskENTER_CRITICAL(g_malloc_mutex);
|
taskENTER_CRITICAL(g_malloc_mutex);
|
||||||
while (b){
|
while (b){
|
||||||
d = DEBUG_BLOCK(b);
|
d = DEBUG_BLOCK(b);
|
||||||
d->head.task[3] = '\0';
|
ets_printf("t=%08X s=%u a=%p\n", d->head.task, b->size, b);
|
||||||
ets_printf("t=%s s=%u a=%p\n", d->head.task?d->head.task:"", b->size, b);
|
|
||||||
b = b->next;
|
b = b->next;
|
||||||
}
|
}
|
||||||
taskEXIT_CRITICAL(g_malloc_mutex);
|
taskEXIT_CRITICAL(g_malloc_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if (configENABLE_MEMORY_DEBUG_DUMP == 1)
|
#if (configENABLE_MEMORY_DEBUG_DUMP >= 1)
|
||||||
size_t mem_debug_malloc_dump(int task, mem_dump_block_t* buffer, size_t size)
|
size_t mem_debug_malloc_dump(TaskHandle_t task, mem_dump_block_t* buffer, size_t size)
|
||||||
{
|
{
|
||||||
os_block_t *b = g_malloc_list.next;
|
os_block_t *b = g_malloc_list.next;
|
||||||
debug_block_t *d;
|
debug_block_t *d;
|
||||||
int btask;
|
TaskHandle_t btask;
|
||||||
size_t remaining = size;
|
size_t remaining = size;
|
||||||
|
|
||||||
taskENTER_CRITICAL(g_malloc_mutex);
|
taskENTER_CRITICAL(g_malloc_mutex);
|
||||||
while (b && remaining > 0) {
|
while (b && remaining > 0) {
|
||||||
d = DEBUG_BLOCK(b);
|
d = DEBUG_BLOCK(b);
|
||||||
btask = *(int*)d->head.task;
|
btask = d->head.task;
|
||||||
if (task) {
|
if (task) {
|
||||||
if (btask != task) {
|
if (btask != task) {
|
||||||
b = b->next;
|
b = b->next;
|
||||||
|
@ -83,7 +82,7 @@ size_t mem_debug_malloc_dump(int task, mem_dump_block_t* buffer, size_t size)
|
||||||
b = b->next;
|
b = b->next;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
*(int*)buffer->task = btask;
|
buffer->task = btask;
|
||||||
buffer->address = (void*)b;
|
buffer->address = (void*)b;
|
||||||
buffer->size = b->size;
|
buffer->size = b->size;
|
||||||
buffer->xtag = b->xtag;
|
buffer->xtag = b->xtag;
|
||||||
|
@ -94,6 +93,67 @@ size_t mem_debug_malloc_dump(int task, mem_dump_block_t* buffer, size_t size)
|
||||||
taskEXIT_CRITICAL(g_malloc_mutex);
|
taskEXIT_CRITICAL(g_malloc_mutex);
|
||||||
return size - remaining;
|
return size - remaining;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t mem_debug_malloc_dump_totals(mem_dump_totals_t* totals, size_t* ntotal, size_t max,
|
||||||
|
TaskHandle_t* tasks, size_t ntasks,
|
||||||
|
mem_dump_block_t* buffer, size_t size)
|
||||||
|
{
|
||||||
|
os_block_t *b = g_malloc_list.next;
|
||||||
|
debug_block_t *d;
|
||||||
|
TaskHandle_t btask;
|
||||||
|
size_t count = *ntotal;
|
||||||
|
size_t remaining = size;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
taskENTER_CRITICAL(g_malloc_mutex);
|
||||||
|
while (b && remaining > 0) {
|
||||||
|
d = DEBUG_BLOCK(b);
|
||||||
|
btask = d->head.task;
|
||||||
|
int tag = b->xtag;
|
||||||
|
if (tag >= NUM_USED_TAGS) {
|
||||||
|
b = b->next;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
size_t index;
|
||||||
|
for (index = 0; index < count; ++index) {
|
||||||
|
if (totals[index].task == btask)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (index < count)
|
||||||
|
totals[index].after[tag] += b->size;
|
||||||
|
else {
|
||||||
|
if (count < max) {
|
||||||
|
totals[count].task = btask;
|
||||||
|
for (i = 0; i < NUM_USED_TAGS; ++i) {
|
||||||
|
totals[count].before[i] = 0;
|
||||||
|
totals[count].after[i] = 0;
|
||||||
|
}
|
||||||
|
totals[count].after[tag] = b->size;
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tasks) {
|
||||||
|
for (i = 0; i < ntasks; ++i) {
|
||||||
|
if (btask == tasks[i])
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i == ntasks) {
|
||||||
|
b = b->next;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buffer->task = btask;
|
||||||
|
buffer->address = (void*)b;
|
||||||
|
buffer->size = b->size;
|
||||||
|
buffer->xtag = b->xtag;
|
||||||
|
++buffer;
|
||||||
|
--remaining;
|
||||||
|
b = b->next;
|
||||||
|
}
|
||||||
|
taskEXIT_CRITICAL(g_malloc_mutex);
|
||||||
|
*ntotal = count;
|
||||||
|
return size - remaining;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void mem_debug_show(void)
|
void mem_debug_show(void)
|
||||||
|
@ -114,11 +174,11 @@ void mem_check_block(void* data)
|
||||||
MEM_DEBUG("check block data=%p\n", data);
|
MEM_DEBUG("check block data=%p\n", data);
|
||||||
if (data && (HEAD_DOG(b) == DEBUG_DOG_VALUE)){
|
if (data && (HEAD_DOG(b) == DEBUG_DOG_VALUE)){
|
||||||
if (TAIL_DOG(b) != DEBUG_DOG_VALUE){
|
if (TAIL_DOG(b) != DEBUG_DOG_VALUE){
|
||||||
ets_printf("f task=%s a=%p h=%08x t=%08x\n", b->head.task?b->head.task:"", b, HEAD_DOG(b), TAIL_DOG(b));
|
ets_printf("f task=%08X a=%p h=%08x t=%08x\n", b->head.task, b, HEAD_DOG(b), TAIL_DOG(b));
|
||||||
DOG_ASSERT();
|
DOG_ASSERT();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ets_printf("f task=%s a=%p h=%08x\n", b->head.task?b->head.task:"", b, HEAD_DOG(b));\
|
ets_printf("f task=%08X a=%p h=%08x\n", b->head.task, b, HEAD_DOG(b));\
|
||||||
DOG_ASSERT();
|
DOG_ASSERT();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,22 +186,13 @@ void mem_check_block(void* data)
|
||||||
void mem_init_dog(void *data)
|
void mem_init_dog(void *data)
|
||||||
{
|
{
|
||||||
debug_block_t *b = DEBUG_BLOCK(data);
|
debug_block_t *b = DEBUG_BLOCK(data);
|
||||||
xTaskHandle task;
|
|
||||||
|
|
||||||
MEM_DEBUG("init dog, data=%p debug_block=%p block_size=%x\n", data, b, b->os_block.size);
|
MEM_DEBUG("init dog, data=%p debug_block=%p block_size=%x\n", data, b, b->os_block.size);
|
||||||
if (!data) return;
|
if (!data) return;
|
||||||
#if (INCLUDE_pcTaskGetTaskName == 1)
|
#if (INCLUDE_pcTaskGetTaskName == 1)
|
||||||
task = xTaskGetCurrentTaskHandle();
|
b->head.task = xTaskGetCurrentTaskHandle();
|
||||||
if (task){
|
|
||||||
int name = 0;
|
|
||||||
strncpy((char*)&name, pcTaskGetTaskName(task), 3);
|
|
||||||
*(int*)b->head.task = name;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
*(int*)b->head.task = 0;
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
b->head.task = '\0';
|
b->head.task = 0;
|
||||||
#endif
|
#endif
|
||||||
HEAD_DOG(b) = DEBUG_DOG_VALUE;
|
HEAD_DOG(b) = DEBUG_DOG_VALUE;
|
||||||
TAIL_DOG(b) = DEBUG_DOG_VALUE;
|
TAIL_DOG(b) = DEBUG_DOG_VALUE;
|
||||||
|
@ -176,18 +227,18 @@ void mem_malloc_show(void)
|
||||||
|
|
||||||
while (b){
|
while (b){
|
||||||
debug_b = DEBUG_BLOCK(b);
|
debug_b = DEBUG_BLOCK(b);
|
||||||
ets_printf("%s %p %p %u\n", debug_b->head.task, debug_b, b, b->size);
|
ets_printf("%08X %p %p %u\n", debug_b->head.task, debug_b, b, b->size);
|
||||||
b = b->next;
|
b = b->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if (configENABLE_MEMORY_DEBUG_ABORT == 1)
|
#if (configENABLE_MEMORY_DEBUG_ABORT == 1)
|
||||||
static int abort_enable = 0;
|
static int abort_enable = 0;
|
||||||
static int abort_task = 0;
|
static TaskHandle_t abort_task = 0;
|
||||||
static int abort_size = 0;
|
static int abort_size = 0;
|
||||||
static int abort_count = 0;
|
static int abort_count = 0;
|
||||||
|
|
||||||
void mem_malloc_set_abort(int task, int size, int count)
|
void mem_malloc_set_abort(TaskHandle_t task, int size, int count)
|
||||||
{
|
{
|
||||||
abort_enable = 1;
|
abort_enable = 1;
|
||||||
abort_task = task;
|
abort_task = task;
|
||||||
|
@ -208,11 +259,11 @@ void mem_malloc_block(void *data)
|
||||||
g_malloc_list.next = b;
|
g_malloc_list.next = b;
|
||||||
#if (configENABLE_MEMORY_DEBUG_ABORT == 1)
|
#if (configENABLE_MEMORY_DEBUG_ABORT == 1)
|
||||||
debug_block_t *d = DEBUG_BLOCK(b);
|
debug_block_t *d = DEBUG_BLOCK(b);
|
||||||
if (abort_enable && *(int*)d->head.task == abort_task &&
|
if (abort_enable && (!abort_task || d->head.task == abort_task) &&
|
||||||
(abort_size == 0 || abort_size == b->size)) {
|
(abort_size == 0 || abort_size == b->size)) {
|
||||||
|
ets_printf(" malloc %08X %p %p %u\n", d->head.task, d, b, b->size);
|
||||||
if (--abort_count <= 0)
|
if (--abort_count <= 0)
|
||||||
abort();
|
abort();
|
||||||
ets_printf("%s %p %p %u\n", d->head.task, d, b, b->size);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -243,7 +294,7 @@ void mem_free_block(void *data)
|
||||||
}
|
}
|
||||||
|
|
||||||
debug_b = DEBUG_BLOCK(del);
|
debug_b = DEBUG_BLOCK(del);
|
||||||
ets_printf("%s %p %p %u already free\n", debug_b->head.task, debug_b, del, del->size);
|
ets_printf("%08X %p %p %u already free\n", debug_b->head.task, debug_b, del, del->size);
|
||||||
mem_malloc_show();
|
mem_malloc_show();
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
|
@ -242,7 +242,7 @@
|
||||||
|
|
||||||
#if CONFIG_ENABLE_MEMORY_DEBUG
|
#if CONFIG_ENABLE_MEMORY_DEBUG
|
||||||
#define configENABLE_MEMORY_DEBUG 1
|
#define configENABLE_MEMORY_DEBUG 1
|
||||||
#define configENABLE_MEMORY_DEBUG_DUMP 1
|
#define configENABLE_MEMORY_DEBUG_DUMP 2
|
||||||
#define configENABLE_MEMORY_DEBUG_ABORT 1
|
#define configENABLE_MEMORY_DEBUG_ABORT 1
|
||||||
#else
|
#else
|
||||||
#define configENABLE_MEMORY_DEBUG 0
|
#define configENABLE_MEMORY_DEBUG 0
|
||||||
|
|
|
@ -16,7 +16,7 @@ extern "C" {
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned int dog;
|
unsigned int dog;
|
||||||
char task[4];
|
TaskHandle_t task;
|
||||||
unsigned int pc;
|
unsigned int pc;
|
||||||
}block_head_t;
|
}block_head_t;
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ typedef struct {
|
||||||
|
|
||||||
typedef struct _mem_dbg_info{
|
typedef struct _mem_dbg_info{
|
||||||
void *addr;
|
void *addr;
|
||||||
char *task;
|
TaskHandle_t task;
|
||||||
uint32_t pc;
|
uint32_t pc;
|
||||||
uint32_t time;
|
uint32_t time;
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
|
@ -71,19 +71,29 @@ extern void mem_free_block(void *data);
|
||||||
extern void mem_check_all(void* pv);
|
extern void mem_check_all(void* pv);
|
||||||
extern void mem_debug_malloc_show(void);
|
extern void mem_debug_malloc_show(void);
|
||||||
#if (configENABLE_MEMORY_DEBUG_ABORT == 1)
|
#if (configENABLE_MEMORY_DEBUG_ABORT == 1)
|
||||||
extern void mem_malloc_set_abort(int task, int size, int count);
|
extern void mem_malloc_set_abort(TaskHandle_t task, int size, int count);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (configENABLE_MEMORY_DEBUG_DUMP == 1)
|
#if (configENABLE_MEMORY_DEBUG_DUMP >= 1)
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char task[4];
|
TaskHandle_t task;
|
||||||
void* address;
|
void* address;
|
||||||
int size: 24; /*<< The size of the free block. */
|
int size: 24; /*<< The size of the free block. */
|
||||||
int xtag: 7; /*<< Tag of this region */
|
int xtag: 7; /*<< Tag of this region */
|
||||||
int xAllocated: 1; /*<< 1 if allocated */
|
int xAllocated: 1; /*<< 1 if allocated */
|
||||||
} mem_dump_block_t;
|
} mem_dump_block_t;
|
||||||
|
|
||||||
extern size_t mem_debug_malloc_dump(int task, mem_dump_block_t* buffer, size_t size);
|
#define NUM_USED_TAGS 3
|
||||||
|
typedef struct {
|
||||||
|
TaskHandle_t task;
|
||||||
|
int before[NUM_USED_TAGS];
|
||||||
|
int after[NUM_USED_TAGS];
|
||||||
|
} mem_dump_totals_t;
|
||||||
|
|
||||||
|
extern size_t mem_debug_malloc_dump(TaskHandle_t task, mem_dump_block_t* buffer, size_t size);
|
||||||
|
extern size_t mem_debug_malloc_dump_totals(mem_dump_totals_t* totals, size_t* ntotal, size_t max,
|
||||||
|
TaskHandle_t* tasks, size_t ntasks,
|
||||||
|
mem_dump_block_t* buffer, size_t size);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
Loading…
Reference in a new issue