You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2022/02/26 06:32:53 UTC
[incubator-nuttx] 03/06: mm/dump: add pid and backtrace for every memory node
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 <do...@xiaomi.com>
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 <do...@xiaomi.com>
---
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));