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:52 UTC

[incubator-nuttx] 02/06: procfs: add memdump interface to dump used/free memory info

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 c5ba9261bcde94025e64f20eebe4f22592f84bc1
Author: Jiuzhu Dong <do...@xiaomi.com>
AuthorDate: Thu Jan 6 20:44:17 2022 +0800

    procfs: add memdump interface to dump used/free memory info
    
    usage:echo <used/free> > /proc/memdump
    echo used > /proc/memdump // output all used memory node info(address + size)
    echo free > /proc/memdump // output all free memory node info(address + size)
    
    Signed-off-by: Jiuzhu Dong <do...@xiaomi.com>
---
 arch/sim/src/sim/up_heap.c   |  12 +++++
 fs/procfs/Kconfig            |   4 ++
 fs/procfs/fs_procfs.c        |   4 ++
 fs/procfs/fs_procfsmeminfo.c | 121 +++++++++++++++++++++++++++++++++++++------
 include/nuttx/mm/mm.h        |   1 +
 mm/mm_heap/Make.defs         |   2 +-
 mm/mm_heap/mm_memdump.c      | 121 +++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 249 insertions(+), 16 deletions(-)

diff --git a/arch/sim/src/sim/up_heap.c b/arch/sim/src/sim/up_heap.c
index 196c6aa..d05c746 100644
--- a/arch/sim/src/sim/up_heap.c
+++ b/arch/sim/src/sim/up_heap.c
@@ -389,6 +389,18 @@ int mm_mallinfo(FAR struct mm_heap_s *heap, FAR struct mallinfo *info)
   return 0;
 }
 
+/****************************************************************************
+ * Name: mm_memdump
+ *
+ * Description:
+ *   mm_memdump returns a memory info about specified pid of task/thread.
+ *
+ ****************************************************************************/
+
+void mm_memdump(FAR struct mm_heap_s *heap, pid_t pid)
+{
+}
+
 #ifdef CONFIG_DEBUG_MM
 
 /****************************************************************************
diff --git a/fs/procfs/Kconfig b/fs/procfs/Kconfig
index 6d28080..f5c275f 100644
--- a/fs/procfs/Kconfig
+++ b/fs/procfs/Kconfig
@@ -96,6 +96,10 @@ config FS_PROCFS_EXCLUDE_MEMINFO
 	bool "Exclude meminfo"
 	default n
 
+config FS_PROCFS_EXCLUDE_MEMDUMP
+	bool "Exclude memdump"
+	default n
+
 config FS_PROCFS_INCLUDE_PROGMEM
 	bool "Include prog mem"
 	default n
diff --git a/fs/procfs/fs_procfs.c b/fs/procfs/fs_procfs.c
index 6d04af6..0c69f8a 100644
--- a/fs/procfs/fs_procfs.c
+++ b/fs/procfs/fs_procfs.c
@@ -66,6 +66,7 @@ extern const struct procfs_operations irq_operations;
 extern const struct procfs_operations cpuload_operations;
 extern const struct procfs_operations critmon_operations;
 extern const struct procfs_operations meminfo_operations;
+extern const struct procfs_operations memdump_operations;
 extern const struct procfs_operations iobinfo_operations;
 extern const struct procfs_operations module_operations;
 extern const struct procfs_operations uptime_operations;
@@ -115,6 +116,9 @@ static const struct procfs_entry_s g_procfs_entries[] =
 
 #ifndef CONFIG_FS_PROCFS_EXCLUDE_MEMINFO
   { "meminfo",       &meminfo_operations,         PROCFS_FILE_TYPE   },
+#ifndef CONFIG_FS_PROCFS_EXCLUDE_MEMDUMP
+  { "memdump",       &memdump_operations,         PROCFS_FILE_TYPE   },
+#endif
 #endif
 
 #if defined(CONFIG_MM_IOB) && !defined(CONFIG_FS_PROCFS_EXCLUDE_IOBINFO)
diff --git a/fs/procfs/fs_procfsmeminfo.c b/fs/procfs/fs_procfsmeminfo.c
index 0156347..13d86da 100644
--- a/fs/procfs/fs_procfsmeminfo.c
+++ b/fs/procfs/fs_procfsmeminfo.c
@@ -94,6 +94,12 @@ static void    meminfo_progmem(FAR struct progmem_info_s *progmem);
 static int     meminfo_open(FAR struct file *filep, FAR const char *relpath,
                  int oflags, mode_t mode);
 static int     meminfo_close(FAR struct file *filep);
+#ifndef CONFIG_FS_PROCFS_EXCLUDE_MEMDUMP
+static ssize_t memdump_read(FAR struct file *filep, FAR char *buffer,
+                             size_t buflen);
+static ssize_t memdump_write(FAR struct file *filep, FAR const char *buffer,
+                             size_t buflen);
+#endif
 static ssize_t meminfo_read(FAR struct file *filep, FAR char *buffer,
                  size_t buflen);
 static int     meminfo_dup(FAR const struct file *oldp,
@@ -123,6 +129,22 @@ const struct procfs_operations meminfo_operations =
   meminfo_stat    /* stat */
 };
 
+#ifndef CONFIG_FS_PROCFS_EXCLUDE_MEMDUMP
+const struct procfs_operations memdump_operations =
+{
+  meminfo_open,   /* open */
+  meminfo_close,  /* close */
+  memdump_read,   /* read */
+  memdump_write,  /* write */
+  meminfo_dup,    /* dup */
+  NULL,           /* opendir */
+  NULL,           /* closedir */
+  NULL,           /* readdir */
+  NULL,           /* rewinddir */
+  meminfo_stat    /* stat */
+};
+#endif
+
 FAR struct procfs_meminfo_entry_s *g_procfs_meminfo = NULL;
 
 /****************************************************************************
@@ -206,22 +228,9 @@ static int meminfo_open(FAR struct file *filep, FAR const char *relpath,
 
   finfo("Open '%s'\n", relpath);
 
-  /* PROCFS is read-only.  Any attempt to open with any kind of write
-   * access is not permitted.
-   *
-   * REVISIT:  Write-able proc files could be quite useful.
-   */
-
-  if ((oflags & O_WRONLY) != 0 || (oflags & O_RDONLY) == 0)
-    {
-      ferr("ERROR: Only O_RDONLY supported\n");
-      return -EACCES;
-    }
-
   /* Allocate a container to hold the file attributes */
 
-  procfile = (FAR struct meminfo_file_s *)
-    kmm_zalloc(sizeof(struct meminfo_file_s));
+  procfile = kmm_zalloc(sizeof(struct meminfo_file_s));
   if (!procfile)
     {
       ferr("ERROR: Failed to allocate file attributes\n");
@@ -230,7 +239,7 @@ static int meminfo_open(FAR struct file *filep, FAR const char *relpath,
 
   /* Save the attributes as the open-specific state in filep->f_priv */
 
-  filep->f_priv = (FAR void *)procfile;
+  filep->f_priv = procfile;
   return OK;
 }
 
@@ -383,6 +392,88 @@ static ssize_t meminfo_read(FAR struct file *filep, FAR char *buffer,
 }
 
 /****************************************************************************
+ * Name: memdump_read
+ ****************************************************************************/
+
+#ifndef CONFIG_FS_PROCFS_EXCLUDE_MEMDUMP
+static ssize_t memdump_read(FAR struct file *filep, FAR char *buffer,
+                            size_t buflen)
+{
+  FAR struct meminfo_file_s *procfile;
+  size_t linesize;
+  size_t copysize;
+  size_t totalsize;
+  off_t offset;
+
+  finfo("buffer=%p buflen=%d\n", buffer, (int)buflen);
+
+  DEBUGASSERT(filep != NULL && buffer != NULL && buflen > 0);
+  offset = filep->f_pos;
+
+  /* Recover our private data from the struct file instance */
+
+  procfile = (FAR struct meminfo_file_s *)filep->f_priv;
+  DEBUGASSERT(procfile);
+
+  linesize  = procfs_snprintf(procfile->line, MEMINFO_LINELEN,
+                              "usage: <used/free>\n");
+
+  copysize  = procfs_memcpy(procfile->line, linesize, buffer, buflen,
+                            &offset);
+  totalsize = copysize;
+  buffer   += copysize;
+  buflen   -= copysize;
+  linesize  = procfs_snprintf(procfile->line, MEMINFO_LINELEN, "%s",
+                              "used: dump all allocated node\n"
+                              "free: dump all free node\n");
+
+  totalsize += procfs_memcpy(procfile->line, linesize, buffer, buflen,
+                             &offset);
+  filep->f_pos += totalsize;
+  return totalsize;
+}
+#endif
+
+/****************************************************************************
+ * Name: memdump_write
+ ****************************************************************************/
+
+#ifndef CONFIG_FS_PROCFS_EXCLUDE_MEMDUMP
+static ssize_t memdump_write(FAR struct file *filep, FAR const char *buffer,
+                             size_t buflen)
+{
+  FAR const struct procfs_meminfo_entry_s *entry;
+  FAR struct meminfo_file_s *procfile;
+  pid_t pid = -1;
+
+  DEBUGASSERT(filep != NULL && buffer != NULL && buflen > 0);
+
+  /* Recover our private data from the struct file instance */
+
+  procfile = filep->f_priv;
+  DEBUGASSERT(procfile);
+
+  switch (buffer[0])
+    {
+      case 'u':
+        pid = -1;
+        break;
+
+      case 'f':
+        pid = -2;
+        break;
+    }
+
+  for (entry = g_procfs_meminfo; entry != NULL; entry = entry->next)
+    {
+      mm_memdump(entry->user_data, pid);
+    }
+
+  return buflen;
+}
+#endif
+
+/****************************************************************************
  * Name: meminfo_dup
  *
  * Description:
diff --git a/include/nuttx/mm/mm.h b/include/nuttx/mm/mm.h
index fa9e3a1..246a1b6 100644
--- a/include/nuttx/mm/mm.h
+++ b/include/nuttx/mm/mm.h
@@ -296,6 +296,7 @@ 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 ************************************/
 
diff --git a/mm/mm_heap/Make.defs b/mm/mm_heap/Make.defs
index c9c0c1c..fdeb15d 100644
--- a/mm/mm_heap/Make.defs
+++ b/mm/mm_heap/Make.defs
@@ -25,7 +25,7 @@ ifeq ($(CONFIG_MM_DEFAULT_MANAGER),y)
 CSRCS += mm_initialize.c mm_sem.c mm_addfreechunk.c mm_size2ndx.c
 CSRCS += mm_malloc_size.c mm_shrinkchunk.c mm_brkaddr.c mm_calloc.c
 CSRCS += mm_extend.c mm_free.c mm_mallinfo.c mm_malloc.c mm_foreach.c
-CSRCS += mm_memalign.c mm_realloc.c mm_zalloc.c mm_heapmember.c
+CSRCS += mm_memalign.c mm_realloc.c mm_zalloc.c mm_heapmember.c mm_memdump.c
 
 ifeq ($(CONFIG_DEBUG_MM),y)
 CSRCS += mm_checkcorruption.c
diff --git a/mm/mm_heap/mm_memdump.c b/mm/mm_heap/mm_memdump.c
new file mode 100644
index 0000000..b3b5a5a
--- /dev/null
+++ b/mm/mm_heap/mm_memdump.c
@@ -0,0 +1,121 @@
+/****************************************************************************
+ * mm/mm_heap/mm_memdump.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdio.h>
+#include <malloc.h>
+#include <assert.h>
+#include <debug.h>
+
+#include <nuttx/mm/mm.h>
+
+#include "mm_heap/mm.h"
+
+struct memdump_info_s
+{
+  pid_t pid;
+  int   blks;
+  int   size;
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static void memdump_handler(FAR struct mm_allocnode_s *node, FAR void *arg)
+{
+  FAR struct memdump_info_s *info = arg;
+
+  if ((node->preceding & MM_ALLOC_BIT) != 0)
+    {
+      DEBUGASSERT(node->size >= SIZEOF_MM_ALLOCNODE);
+      if (info->pid == -1)
+        {
+          info->blks++;
+          info->size += node->size;
+          syslog(LOG_INFO, "%12p%12" PRIu32 "\n",
+                 ((FAR char *)node + SIZEOF_MM_ALLOCNODE),
+                 node->size);
+        }
+    }
+  else
+    {
+      FAR struct mm_freenode_s *fnode = (FAR void *)node;
+
+      DEBUGASSERT(node->size >= SIZEOF_MM_FREENODE);
+      DEBUGASSERT(fnode->blink->flink == fnode);
+      DEBUGASSERT(fnode->blink->size <= fnode->size);
+      DEBUGASSERT(fnode->flink == NULL ||
+                  fnode->flink->blink == fnode);
+      DEBUGASSERT(fnode->flink == NULL ||
+                  fnode->flink->size == 0 ||
+                  fnode->flink->size >= fnode->size);
+
+      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);
+        }
+    }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: mm_memdump
+ *
+ * Description:
+ *   mm_memdump returns a memory info about specified pid of task/thread.
+ *
+ ****************************************************************************/
+
+void mm_memdump(FAR struct mm_heap_s *heap, pid_t pid)
+{
+  struct memdump_info_s info;
+
+  if (pid == -1)
+    {
+      syslog(LOG_INFO, "Dump all used memory node info:\n");
+    }
+  else if (pid == -2)
+    {
+      syslog(LOG_INFO, "Dump all free memory node info:\n");
+    }
+
+  syslog(LOG_INFO, "%12s%12s\n", "Address", "Size");
+
+  info.blks = 0;
+  info.size = 0;
+  info.pid  = pid;
+  mm_foreach(heap, memdump_handler, &info);
+
+  syslog(LOG_INFO, "%12s%12s\n", "Total Blks", "Total Size");
+  syslog(LOG_INFO, "%12d%12d\n", info.blks, info.size);
+}