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