mirror of
https://github.com/apache/nuttx.git
synced 2026-05-26 10:46:28 +08:00
gdb/mmleak: add diagnose API to report details of the leak
Example of json dump:
{
"title": "Memory Leak Report",
"summary": "Total 105 blks, 22768 bytes leaked",
"result": "fail",
"command": "mm leak",
"data": [
{
"count": 1,
"pid": 0,
"size": 48,
"address": 1100447608,
"seqno": 0,
"alive": true,
"backtrace": []
},
{
"count": 1,
"pid": 4,
"size": 368,
"address": 1100549056,
"seqno": 1041,
"alive": false,
"backtrace": [
{
"address": 1076428472,
"function": "<mm_zalloc+8>",
"source": "mm_heap/mm_zalloc.c:45"
},
{
"address": 1076424018,
"function": "<mm_calloc+18>",
"source": "mm_heap/mm_calloc.c:57"
},
{
"address": 1076419750,
"function": "<calloc+22>",
"source": "umm_heap/umm_calloc.c:73"
},
....
]
},
}
Signed-off-by: xuxingliang <xuxingliang@xiaomi.com>
This commit is contained in:
@@ -22,7 +22,7 @@ import bisect
|
|||||||
import json
|
import json
|
||||||
import time
|
import time
|
||||||
from os import path
|
from os import path
|
||||||
from typing import Dict, Generator, List
|
from typing import Dict, Generator, List, Tuple
|
||||||
|
|
||||||
import gdb
|
import gdb
|
||||||
|
|
||||||
@@ -100,13 +100,9 @@ class MMLeak(gdb.Command):
|
|||||||
|
|
||||||
return nodes
|
return nodes
|
||||||
|
|
||||||
def invoke(self, arg: str, from_tty: bool) -> None:
|
def collect_leaks(
|
||||||
heaps = memdump.get_heaps("g_mmheap")
|
self, heaps: List[mm.MMHeap]
|
||||||
pids = [int(tcb["pid"]) for tcb in utils.get_tcbs()]
|
) -> Dict[memdump.MMNodeDump, List[memdump.MMNodeDump]]:
|
||||||
|
|
||||||
def is_pid_alive(pid):
|
|
||||||
return pid in pids
|
|
||||||
|
|
||||||
t = time.time()
|
t = time.time()
|
||||||
print("Loading globals from elf...", flush=True, end="")
|
print("Loading globals from elf...", flush=True, end="")
|
||||||
good_nodes = self.global_nodes() # Global memory are all good.
|
good_nodes = self.global_nodes() # Global memory are all good.
|
||||||
@@ -155,15 +151,67 @@ class MMLeak(gdb.Command):
|
|||||||
|
|
||||||
print(f" {time.time() - t:.2f}s", flush=True, end="\n")
|
print(f" {time.time() - t:.2f}s", flush=True, end="\n")
|
||||||
|
|
||||||
leak_nodes = memdump.group_nodes(nodes_dict[addr] for addr in sorted_addr)
|
return memdump.group_nodes((nodes_dict[addr] for addr in sorted_addr))
|
||||||
|
|
||||||
|
def _iterate_leaks(
|
||||||
|
self, nodes: Dict[memdump.MMNodeDump, List[memdump.MMNodeDump]]
|
||||||
|
) -> Generator[Tuple[memdump.MMNodeDump, bool, int], None, None]:
|
||||||
|
pids = [int(tcb["pid"]) for tcb in utils.get_tcbs()]
|
||||||
|
|
||||||
|
def is_pid_alive(pid):
|
||||||
|
return pid in pids
|
||||||
|
|
||||||
|
for node in nodes.keys():
|
||||||
|
count = len(nodes[node])
|
||||||
|
yield node, is_pid_alive(node.pid), count
|
||||||
|
|
||||||
|
def invoke(self, arg: str, from_tty: bool) -> None:
|
||||||
|
heaps = memdump.get_heaps("g_mmheap")
|
||||||
|
|
||||||
|
leak_nodes = self.collect_leaks(heaps)
|
||||||
memdump.print_header()
|
memdump.print_header()
|
||||||
total_blk = total_size = 0
|
total_blk = total_size = 0
|
||||||
for node in leak_nodes.keys():
|
for node, alive, count in self._iterate_leaks(leak_nodes):
|
||||||
count = len(leak_nodes[node])
|
|
||||||
total_blk += count
|
total_blk += count
|
||||||
total_size += count * node.nodesize
|
total_size += count * node.nodesize
|
||||||
memdump.print_node(
|
memdump.print_node(node, alive, count=count)
|
||||||
node, is_pid_alive(node.pid), count=len(leak_nodes[node])
|
|
||||||
)
|
|
||||||
|
|
||||||
print(f"Leaked {total_blk} blks, {total_size} bytes")
|
print(f"Leaked {total_blk} blks, {total_size} bytes")
|
||||||
|
|
||||||
|
def diagnose(self, *args, **kwargs):
|
||||||
|
heaps = memdump.get_heaps("g_mmheap")
|
||||||
|
leak_nodes = self.collect_leaks(heaps)
|
||||||
|
total_blk = total_size = 0
|
||||||
|
data = []
|
||||||
|
for node, alive, count in self._iterate_leaks(leak_nodes):
|
||||||
|
total_blk += count
|
||||||
|
total_size += count * node.nodesize
|
||||||
|
info = {
|
||||||
|
"count": count,
|
||||||
|
"pid": node.pid,
|
||||||
|
"size": node.nodesize,
|
||||||
|
"address": node.address,
|
||||||
|
"seqno": node.seqno,
|
||||||
|
"alive": alive,
|
||||||
|
"backtrace": [],
|
||||||
|
}
|
||||||
|
|
||||||
|
if mm.CONFIG_MM_BACKTRACE and node.backtrace and node.backtrace[0]:
|
||||||
|
bt = utils.Backtrace(node.backtrace)
|
||||||
|
info["backtrace"] = [
|
||||||
|
{
|
||||||
|
"address": addr,
|
||||||
|
"function": func,
|
||||||
|
"source": source,
|
||||||
|
}
|
||||||
|
for addr, func, source in bt.backtrace
|
||||||
|
]
|
||||||
|
data.append(info)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"title": "Memory Leak Report",
|
||||||
|
"summary": f"Total {total_blk} blks, {total_size} bytes leaked",
|
||||||
|
"result": "fail" if total_blk else "pass",
|
||||||
|
"command": "mm leak",
|
||||||
|
"data": data,
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user