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/nuttx.git
commit 06a696076a1fed2cdca1707fe43489b2fbf3a0e4 Author: xuxingliang <xuxingli...@xiaomi.com> AuthorDate: Thu Nov 21 20:32:30 2024 +0800 gdb/memdump: reorganize the memdump parameters Make the dump_nodes etc more common to use. Signed-off-by: xuxingliang <xuxingli...@xiaomi.com> --- tools/gdb/nuttxgdb/memdump.py | 179 ++++++++++++++++++++++-------------------- tools/gdb/nuttxgdb/memleak.py | 2 +- 2 files changed, 96 insertions(+), 85 deletions(-) diff --git a/tools/gdb/nuttxgdb/memdump.py b/tools/gdb/nuttxgdb/memdump.py index 48f9191af4..823f7b600f 100644 --- a/tools/gdb/nuttxgdb/memdump.py +++ b/tools/gdb/nuttxgdb/memdump.py @@ -46,8 +46,7 @@ class MMNodeDump(Protocol): def read_memory(self) -> memoryview: ... -def dump_nodes( - heaps: List[mm.MMHeap], +def filter_node( pid=None, nodesize=None, used=None, @@ -55,30 +54,41 @@ def dump_nodes( seqmin=None, seqmax=None, orphan=None, - no_heap=False, - no_pool=False, no_pid=None, + no_heap=None, + no_pool=None, +) -> bool: + return lambda node: ( + (pid is None or node.pid == pid) + and (no_pid is None or node.pid != no_pid) + and (nodesize is None or node.nodesize == nodesize) + and (not used or not node.is_free) + and (not free or node.is_free) + and (seqmin is None or node.seqno >= seqmin) + and (seqmax is None or node.seqno <= seqmax) + and (not orphan or node.is_orphan) + ) + + +def dump_nodes( + heaps: List[mm.MMHeap], + filters=None, ) -> Generator[MMNodeDump, None, None]: - def filter_node(node: MMNodeDump) -> bool: - return ( - (pid is None or node.pid == pid) - and (no_pid is None or node.pid != no_pid) - and (nodesize is None or node.nodesize == nodesize) - and (not used or not node.is_free) - and (not free or node.is_free) - and (seqmin is None or node.seqno >= seqmin) - and (seqmax is None or node.seqno <= seqmax) - and (not orphan or node.is_orphan) - ) + no_heap = filters and filters.get("no_heap") + no_pool = filters and filters.get("no_heap") if not no_heap: - yield from (node for heap in heaps for node in filter(filter_node, heap.nodes)) + yield from ( + node + for heap in heaps + for node in filter(filter_node(**filters), heap.nodes) + ) if not no_pool: yield from ( blk for pool in mm.get_pools(heaps) - for blk in filter(filter_node, pool.blks) + for blk in filter(filter_node(**filters), pool.blks) ) @@ -148,18 +158,6 @@ class MMDump(gdb.Command): # define memdump as mm dump utils.alias("memdump", "mm dump") - def find(self, heaps: List[mm.MMHeap], addr): - """Find the node that contains the address""" - # Search pools firstly. - for pool in mm.get_pools(heaps): - if blk := pool.find(addr): - return blk - - # Search heaps - for heap in heaps: - if node := heap.find(addr): - return node - def parse_args(self, arg): parser = argparse.ArgumentParser(description=self.__doc__) parser.add_argument( @@ -167,7 +165,7 @@ class MMDump(gdb.Command): "--address", type=str, default=None, - help="The address to inspect", + help="Find the node that contains the address and exit", ) parser.add_argument( @@ -215,6 +213,12 @@ class MMDump(gdb.Command): action="store_true", help="Do not print backtrace", ) + parser.add_argument( + "--no-reverse", + "--nor", + action="store_true", + help="Do not reverse the sort result", + ) # add option to sort the node by size or count parser.add_argument( @@ -230,38 +234,52 @@ class MMDump(gdb.Command): except SystemExit: return + def find_address(self, addr, heap=None, log=None): + """Find the node that contains the address from memdump log or live dump.""" + addr = int(gdb.parse_and_eval(addr)) + heaps = [mm.MMHeap(gdb.parse_and_eval(heap))] if heap else mm.get_heaps() + + # Find pool firstly + node = next( + (blk for pool in mm.get_pools(heaps) if (blk := pool.find(addr))), None + ) + + # Try heap if not found in pool + node = node or next((node for heap in heaps if (node := heap.find(addr))), None) + + return addr, node + + def collect_nodes(self, heap, log=None, filters=None): + heaps = [mm.MMHeap(gdb.parse_and_eval(heap))] if heap else mm.get_heaps() + nodes = dump_nodes(heaps, filters) + + return nodes + def invoke(self, arg: str, from_tty: bool) -> None: if not (args := self.parse_args(arg)): return - heaps = ( - [mm.MMHeap(gdb.parse_and_eval(args.heap))] if args.heap else mm.get_heaps() - ) - pids = [int(tcb["pid"]) for tcb in utils.get_tcbs()] - print_header() + pids = [int(tcb["pid"]) for tcb in utils.get_tcbs()] + def printnode(node, count): print_node(node, node.pid in pids, count, no_backtrace=args.no_backtrace) + # Find the node by address, find directly and then quit if args.address: - addr = int(gdb.parse_and_eval(args.address)) - # Address specified, find and return directly. - node = None - for pool in mm.get_pools(heaps): - if node := pool.find(addr): - break - - if node or (node := self.find(heaps, addr)): - printnode(node, 1) + addr, node = self.find_address(args.address, args.heap, args.log) + if not node: + print(f"Address {addr:#x} not found in any heap") + else: source = "Pool" if node.from_pool else "Heap" - print(f"{addr: #x} found belongs to {source} {node}") + printnode(node, 1) + print(f"{addr: #x} found belongs to {source} - {node}") + if node.prevnode: print(f"prevnode: {node.prevnode}") if node.nextnode: print(f"nextnode: {node.nextnode}") - else: - print(f"Address {addr:#x} not found in any heap") return filters = { @@ -272,21 +290,11 @@ class MMDump(gdb.Command): "seqmin": args.min, "seqmax": args.max, "orphan": args.orphan, + "no_heap": args.no_heap, + "no_pool": args.no_pool, } - heap_nodes = dump_nodes(heaps, **filters, no_heap=args.no_heap, no_pool=True) - pool_nodes = dump_nodes(heaps, **filters, no_heap=True, no_pool=args.no_pool) - - if args.biggest: - # Find the biggest nodes, only applicable to heaps - nodes = sorted( - heap_nodes, - key=lambda node: node.nodesize, - reverse=True, - ) - for node in nodes[: args.top]: - print(f"node@{node.address}: {node}") - return + nodes = self.collect_nodes(args.heap, log=args.log, filters=filters) sort_method = { "count": lambda node: 1, @@ -296,41 +304,44 @@ class MMDump(gdb.Command): "address": lambda node: node.address, } - def sort_nodes(nodes): - nodes = sorted(nodes, key=sort_method[args.sort], reverse=True) + def sort_nodes(nodes, sort=None): + sort = sort or args.sort + nodes = sorted(nodes, key=sort_method[sort], reverse=not args.no_reverse) if args.top is not None: nodes = nodes[: args.top] if args.top > 0 else nodes[args.top :] return nodes + if args.biggest: + # Dump the biggest node is same as sort by nodesize and do not group them + args.sort = "nodesize" + args.no_group = True + if args.no_group: # Print nodes without grouping - nodes = list(heap_nodes) - nodes.extend(pool_nodes) + nodes = list(nodes) for node in sort_nodes(nodes): printnode(node, 1) gdb.write(f"Total blks: {len(nodes)}\n") - return - - # Finally group the nodes and then print - - grouped: Dict[MMNodeDump, MMNodeDump] = defaultdict(list) - grouped = group_nodes(heap_nodes) - grouped = group_nodes(pool_nodes, grouped) - - # Replace the count and size to count grouped nodes - sort_method["count"] = lambda node: len(grouped[node]) - sort_method["size"] = lambda node: node.nodesize * len(grouped[node]) - total_blk = total_size = 0 - for node in sort_nodes(grouped.keys()): - count = len(grouped[node]) - total_blk += count - if node.pid != mm.PID_MM_MEMPOOL: - total_size += count * node.nodesize - printnode(node, count) - - print(f"Total {total_blk} blks, {total_size} bytes") + else: + # Group the nodes and then print + + grouped: Dict[MMNodeDump, MMNodeDump] = defaultdict(list) + grouped = group_nodes(nodes) + + # Replace the count and size to count grouped nodes + sort_method["count"] = lambda node: len(grouped[node]) + sort_method["size"] = lambda node: node.nodesize * len(grouped[node]) + total_blk = total_size = 0 + for node in sort_nodes(grouped.keys()): + count = len(grouped[node]) + total_blk += count + if node.pid != mm.PID_MM_MEMPOOL: + total_size += count * node.nodesize + printnode(node, count) + + print(f"Total {total_blk} blks, {total_size} bytes") class MMfrag(gdb.Command): diff --git a/tools/gdb/nuttxgdb/memleak.py b/tools/gdb/nuttxgdb/memleak.py index 482d1d55d3..7303052033 100644 --- a/tools/gdb/nuttxgdb/memleak.py +++ b/tools/gdb/nuttxgdb/memleak.py @@ -95,7 +95,7 @@ class MMLeak(gdb.Command): sorted_addr = set() t = time.time() print("Gather memory nodes...", flush=True, end="") - for node in memdump.dump_nodes(heaps, used=True, no_pid=mm.PID_MM_MEMPOOL): + for node in memdump.dump_nodes(heaps, {"no_pid": mm.PID_MM_MEMPOOL}): nodes_dict[node.address] = node sorted_addr.add(node.address)