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:
Stephen Casner 2017-11-01 00:32:39 -07:00
parent 88ab5d4830
commit eb9f77247a
3 changed files with 97 additions and 36 deletions

View file

@ -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();
} }

View file

@ -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

View file

@ -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