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));