This is an automated email from the ASF dual-hosted git repository. xiaoxiang pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
commit 2dcc4a359d3fdc080be5c2742af6c496c1d13354 Author: Jiuzhu Dong <[email protected]> AuthorDate: Thu Jan 20 17:17:29 2022 +0800 mm/dump: add pid and backtrace for every memory node usage: echo <pid/used/free> trace > /proc/memdump echo used > /proc/memdump //output all used memory info with backtrace echo free > /proc/memdump //output all free memory info echo 22 > /proc/memdump //output used memory info for task pid is 22 with backtrace Signed-off-by: Jiuzhu Dong <[email protected]> --- fs/procfs/fs_procfsmeminfo.c | 12 +++++++- include/nuttx/mm/mm.h | 5 +++- mm/mm_heap/mm.h | 51 ++++++++++++++++++++++++++-------- mm/mm_heap/mm_initialize.c | 2 ++ mm/mm_heap/mm_malloc.c | 1 + mm/mm_heap/mm_memalign.c | 1 + mm/mm_heap/mm_memdump.c | 65 ++++++++++++++++++++++++++++++++++++-------- mm/mm_heap/mm_realloc.c | 4 +++ 8 files changed, 115 insertions(+), 26 deletions(-) diff --git a/fs/procfs/fs_procfsmeminfo.c b/fs/procfs/fs_procfsmeminfo.c index 13d86da..d15518f 100644 --- a/fs/procfs/fs_procfsmeminfo.c +++ b/fs/procfs/fs_procfsmeminfo.c @@ -415,15 +415,21 @@ static ssize_t memdump_read(FAR struct file *filep, FAR char *buffer, procfile = (FAR struct meminfo_file_s *)filep->f_priv; DEBUGASSERT(procfile); +#ifdef CONFIG_DEBUG_MM + linesize = procfs_snprintf(procfile->line, MEMINFO_LINELEN, + "usage: <pid/used/free>\n" + "pid: dump pid allocated node\n"); +#else linesize = procfs_snprintf(procfile->line, MEMINFO_LINELEN, "usage: <used/free>\n"); +#endif copysize = procfs_memcpy(procfile->line, linesize, buffer, buflen, &offset); totalsize = copysize; buffer += copysize; buflen -= copysize; - linesize = procfs_snprintf(procfile->line, MEMINFO_LINELEN, "%s", + linesize = procfs_snprintf(procfile->line, MEMINFO_LINELEN, "used: dump all allocated node\n" "free: dump all free node\n"); @@ -462,6 +468,10 @@ static ssize_t memdump_write(FAR struct file *filep, FAR const char *buffer, case 'f': pid = -2; break; +#ifdef CONFIG_DEBUG_MM + default: + pid = atoi(buffer); +#endif } for (entry = g_procfs_meminfo; entry != NULL; entry = entry->next) diff --git a/include/nuttx/mm/mm.h b/include/nuttx/mm/mm.h index 246a1b6..aad4e6f 100644 --- a/include/nuttx/mm/mm.h +++ b/include/nuttx/mm/mm.h @@ -296,7 +296,6 @@ void kmm_extend(FAR void *mem, size_t size, int region); struct mallinfo; /* Forward reference */ int mm_mallinfo(FAR struct mm_heap_s *heap, FAR struct mallinfo *info); -void mm_memdump(FAR struct mm_heap_s *heap, pid_t pid); /* Functions contained in kmm_mallinfo.c ************************************/ @@ -304,6 +303,10 @@ void mm_memdump(FAR struct mm_heap_s *heap, pid_t pid); struct mallinfo kmm_mallinfo(void); #endif +/* Functions contained in mm_memdump.c **************************************/ + +void mm_memdump(FAR struct mm_heap_s *heap, pid_t pid); + #ifdef CONFIG_DEBUG_MM /* Functions contained in mm_checkcorruption.c ******************************/ diff --git a/mm/mm_heap/mm.h b/mm/mm_heap/mm.h index 1d7219d..6f442db 100644 --- a/mm/mm_heap/mm.h +++ b/mm/mm_heap/mm.h @@ -30,10 +30,12 @@ #include <nuttx/fs/procfs.h> #include <assert.h> +#include <execinfo.h> #include <sys/types.h> #include <stdbool.h> #include <string.h> #include <semaphore.h> +#include <unistd.h> /**************************************************************************** * Pre-processor Definitions @@ -64,8 +66,8 @@ * REVISIT: We could do better on machines with 16-bit addressing. */ -# define MM_MIN_SHIFT ( 4) /* 16 bytes */ -# define MM_MAX_SHIFT (15) /* 32 Kb */ +# define MM_MIN_SHIFT_ ( 4) /* 16 bytes */ +# define MM_MAX_SHIFT (15) /* 32 Kb */ #elif defined(CONFIG_HAVE_LONG_LONG) /* Four byte offsets; Pointers may be 4 or 8 bytes @@ -73,19 +75,36 @@ */ # if UINTPTR_MAX <= UINT32_MAX -# define MM_MIN_SHIFT ( 4) /* 16 bytes */ +# define MM_MIN_SHIFT_ ( 4) /* 16 bytes */ # elif UINTPTR_MAX <= UINT64_MAX -# define MM_MIN_SHIFT ( 5) /* 32 bytes */ +# define MM_MIN_SHIFT_ ( 5) /* 32 bytes */ # endif -# define MM_MAX_SHIFT (22) /* 4 Mb */ +# define MM_MAX_SHIFT (22) /* 4 Mb */ #else /* Four byte offsets; Pointers must be 4 bytes. * sizeof(struct mm_freenode_s) is 16 bytes. */ -# define MM_MIN_SHIFT ( 4) /* 16 bytes */ -# define MM_MAX_SHIFT (22) /* 4 Mb */ +# define MM_MIN_SHIFT_ ( 4) /* 16 bytes */ +# define MM_MAX_SHIFT (22) /* 4 Mb */ +#endif + +#ifdef CONFIG_DEBUG_MM +# define MM_MIN_SHIFT (MM_MIN_SHIFT_ + 2) +# define MM_BACKTRACE_DEPTH 8 +# define MM_ADD_BACKTRACE(ptr) \ + do \ + { \ + FAR struct mm_allocnode_s *tmp = (FAR struct mm_allocnode_s *)(ptr); \ + tmp->pid = getpid(); \ + memset(tmp->backtrace, 0, sizeof(tmp->backtrace)); \ + backtrace(tmp->backtrace, MM_BACKTRACE_DEPTH); \ + } \ + while (0) +#else +# define MM_ADD_BACKTRACE(ptr) +# define MM_MIN_SHIFT MM_MIN_SHIFT_ #endif /* All other definitions derive from these two */ @@ -140,8 +159,12 @@ typedef uint32_t mmsize_t; struct mm_allocnode_s { - mmsize_t size; /* Size of this chunk */ - mmsize_t preceding; /* Size of the preceding chunk */ +#ifdef CONFIG_DEBUG_MM + uint32_t pid; /* The pid for caller */ + FAR void *backtrace[MM_BACKTRACE_DEPTH]; /* The backtrace buffer for caller */ +#endif + mmsize_t size; /* Size of this chunk */ + mmsize_t preceding; /* Size of the preceding chunk */ }; static_assert(SIZEOF_MM_ALLOCNODE <= MM_MIN_CHUNK, @@ -151,9 +174,13 @@ static_assert(SIZEOF_MM_ALLOCNODE <= MM_MIN_CHUNK, struct mm_freenode_s { - mmsize_t size; /* Size of this chunk */ - mmsize_t preceding; /* Size of the preceding chunk */ - FAR struct mm_freenode_s *flink; /* Supports a doubly linked list */ +#ifdef CONFIG_DEBUG_MM + uint32_t pid; /* The pid for caller */ + FAR void *backtrace[MM_BACKTRACE_DEPTH]; /* The backtrace buffer for caller */ +#endif + mmsize_t size; /* Size of this chunk */ + mmsize_t preceding; /* Size of the preceding chunk */ + FAR struct mm_freenode_s *flink; /* Supports a doubly linked list */ FAR struct mm_freenode_s *blink; }; diff --git a/mm/mm_heap/mm_initialize.c b/mm/mm_heap/mm_initialize.c index bf84db4..5e8b52b 100644 --- a/mm/mm_heap/mm_initialize.c +++ b/mm/mm_heap/mm_initialize.c @@ -117,6 +117,7 @@ void mm_addregion(FAR struct mm_heap_s *heap, FAR void *heapstart, heap->mm_heapstart[IDX] = (FAR struct mm_allocnode_s *) heapbase; + MM_ADD_BACKTRACE(heap->mm_heapstart[IDX]); heap->mm_heapstart[IDX]->size = SIZEOF_MM_ALLOCNODE; heap->mm_heapstart[IDX]->preceding = MM_ALLOC_BIT; node = (FAR struct mm_freenode_s *) @@ -127,6 +128,7 @@ void mm_addregion(FAR struct mm_heap_s *heap, FAR void *heapstart, (heapend - SIZEOF_MM_ALLOCNODE); heap->mm_heapend[IDX]->size = SIZEOF_MM_ALLOCNODE; heap->mm_heapend[IDX]->preceding = node->size | MM_ALLOC_BIT; + MM_ADD_BACKTRACE(heap->mm_heapend[IDX]); #undef IDX diff --git a/mm/mm_heap/mm_malloc.c b/mm/mm_heap/mm_malloc.c index a1262f5..9a94910 100644 --- a/mm/mm_heap/mm_malloc.c +++ b/mm/mm_heap/mm_malloc.c @@ -223,6 +223,7 @@ FAR void *mm_malloc(FAR struct mm_heap_s *heap, size_t size) /* Handle the case of an exact size match */ node->preceding |= MM_ALLOC_BIT; + MM_ADD_BACKTRACE(node); ret = (FAR void *)((FAR char *)node + SIZEOF_MM_ALLOCNODE); } diff --git a/mm/mm_heap/mm_memalign.c b/mm/mm_heap/mm_memalign.c index 1fcd387..0fa3968 100644 --- a/mm/mm_heap/mm_memalign.c +++ b/mm/mm_heap/mm_memalign.c @@ -178,6 +178,7 @@ FAR void *mm_memalign(FAR struct mm_heap_s *heap, size_t alignment, newnode->size = (size_t)next - (size_t)newnode; newnode->preceding = precedingsize | MM_ALLOC_BIT; + MM_ADD_BACKTRACE(newnode); /* Reduce the size of the original chunk and mark it not allocated, */ diff --git a/mm/mm_heap/mm_memdump.c b/mm/mm_heap/mm_memdump.c index b3b5a5a..4cea66d6 100644 --- a/mm/mm_heap/mm_memdump.c +++ b/mm/mm_heap/mm_memdump.c @@ -33,6 +33,20 @@ #include "mm_heap/mm.h" +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#if UINTPTR_MAX <= UINT32_MAX +# define MM_PTR_FMT_WIDTH 11 +#elif UINTPTR_MAX <= UINT64_MAX +# define MM_PTR_FMT_WIDTH 19 +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + struct memdump_info_s { pid_t pid; @@ -51,13 +65,32 @@ static void memdump_handler(FAR struct mm_allocnode_s *node, FAR void *arg) if ((node->preceding & MM_ALLOC_BIT) != 0) { DEBUGASSERT(node->size >= SIZEOF_MM_ALLOCNODE); +#ifndef CONFIG_DEBUG_MM if (info->pid == -1) +#else + if (info->pid == -1 || node->pid == info->pid) +#endif { +#ifndef CONFIG_DEBUG_MM + syslog(LOG_INFO, "%12zu%*p\n", + (size_t)node->size, MM_PTR_FMT_WIDTH, + ((FAR char *)node + SIZEOF_MM_ALLOCNODE)); +#else + int i; + char buf[MM_BACKTRACE_DEPTH * MM_PTR_FMT_WIDTH + 1]; + + for (i = 0; i < MM_BACKTRACE_DEPTH && node->backtrace[i]; i++) + { + sprintf(buf + i * MM_PTR_FMT_WIDTH, " %*p", + MM_PTR_FMT_WIDTH - 3, node->backtrace[i]); + } + + syslog(LOG_INFO, "%6d%12zu%*p%s\n", + (int)node->pid, (size_t)node->size, MM_PTR_FMT_WIDTH, + ((FAR char *)node + SIZEOF_MM_ALLOCNODE), buf); +#endif info->blks++; info->size += node->size; - syslog(LOG_INFO, "%12p%12" PRIu32 "\n", - ((FAR char *)node + SIZEOF_MM_ALLOCNODE), - node->size); } } else @@ -73,13 +106,13 @@ static void memdump_handler(FAR struct mm_allocnode_s *node, FAR void *arg) fnode->flink->size == 0 || fnode->flink->size >= fnode->size); - if (info->pid == -2) + if (info->pid <= -2) { info->blks++; info->size += node->size; - syslog(LOG_INFO, "%12p%12" PRIu32 "\n", - ((FAR char *)node + SIZEOF_MM_ALLOCNODE), - node->size); + syslog(LOG_INFO, "%12zu%*p\n", + (size_t)node->size, MM_PTR_FMT_WIDTH, + ((FAR char *)node + SIZEOF_MM_ALLOCNODE)); } } } @@ -93,24 +126,32 @@ static void memdump_handler(FAR struct mm_allocnode_s *node, FAR void *arg) * * Description: * mm_memdump returns a memory info about specified pid of task/thread. - * + * if pid equals -1, this function will dump all allocated node and output + * backtrace for every allocated node for this heap, if pid equals -2, this + * function will dump all free node for this heap, and if pid is greater + * than or equal to 0, will dump pid allocated node and output backtrace. ****************************************************************************/ void mm_memdump(FAR struct mm_heap_s *heap, pid_t pid) { struct memdump_info_s info; - if (pid == -1) + if (pid >= -1) { syslog(LOG_INFO, "Dump all used memory node info:\n"); +#ifndef CONFIG_DEBUG_MM + syslog(LOG_INFO, "%12s%*s\n", "Size", MM_PTR_FMT_WIDTH, "Address"); +#else + syslog(LOG_INFO, "%6s%12s%*s %s\n", "PID", "Size", MM_PTR_FMT_WIDTH, + "Address", "Backtrace"); +#endif } - else if (pid == -2) + else { syslog(LOG_INFO, "Dump all free memory node info:\n"); + syslog(LOG_INFO, "%12s%*s\n", "Size", MM_PTR_FMT_WIDTH, "Address"); } - syslog(LOG_INFO, "%12s%12s\n", "Address", "Size"); - info.blks = 0; info.size = 0; info.pid = pid; diff --git a/mm/mm_heap/mm_realloc.c b/mm/mm_heap/mm_realloc.c index 1842572..366cbfe 100644 --- a/mm/mm_heap/mm_realloc.c +++ b/mm/mm_heap/mm_realloc.c @@ -128,6 +128,8 @@ FAR void *mm_realloc(FAR struct mm_heap_s *heap, FAR void *oldmem, oldsize - oldnode->size); } + MM_ADD_BACKTRACE(oldnode); + /* Then return the original address */ mm_givesemaphore(heap); @@ -332,6 +334,8 @@ FAR void *mm_realloc(FAR struct mm_heap_s *heap, FAR void *oldmem, } } + MM_ADD_BACKTRACE((FAR char *)newmem - SIZEOF_MM_ALLOCNODE); + mm_givesemaphore(heap); kasan_unpoison(newmem, mm_malloc_size(newmem));
