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 <dongjiuzhu1@xiaomi.com>
This commit is contained in:
Jiuzhu Dong 2022-01-20 17:17:29 +08:00 committed by Xiang Xiao
parent c5ba9261bc
commit 2dcc4a359d
8 changed files with 115 additions and 26 deletions

View File

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

View File

@ -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 ******************************/

View File

@ -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;
};

View File

@ -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

View File

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

View File

@ -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, */

View File

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

View File

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