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:
parent
c5ba9261bc
commit
2dcc4a359d
@ -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)
|
||||
|
@ -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 ******************************/
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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, */
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
|
Loading…
Reference in New Issue
Block a user