From 09714684ace60105a81c539516b945fe4d0b3d65 Mon Sep 17 00:00:00 2001 From: "wensheng.he" Date: Tue, 4 Nov 2014 18:14:21 -0800 Subject: Add a new command to summarize memory usage by function addresses in dmprof The output format is: vss1;rss1;addr1;symbol1 vss2;rss2;addr2;symbol2 ... The symbol is related to the addr. If the binary file has symbols, it just same as before:function@sourcefile. Otherwise it will show the pathname the addr belongs to (mainly it's the library). This new command could be helpful for lcation leaks. R=kouhei@chromium.org BUG=427393 Review URL: https://codereview.chromium.org/700773002 Cr-Commit-Position: refs/heads/master@{#302745} --- tools/deep_memory_profiler/dmprof.py | 1 + tools/deep_memory_profiler/subcommands/__init__.py | 1 + tools/deep_memory_profiler/subcommands/addr.py | 88 ++++++++++++++++++++++ 3 files changed, 90 insertions(+) create mode 100644 tools/deep_memory_profiler/subcommands/addr.py diff --git a/tools/deep_memory_profiler/dmprof.py b/tools/deep_memory_profiler/dmprof.py index 0cb030a..85c1f6d 100644 --- a/tools/deep_memory_profiler/dmprof.py +++ b/tools/deep_memory_profiler/dmprof.py @@ -19,6 +19,7 @@ LOGGER = logging.getLogger('dmprof') def main(): COMMANDS = { + 'addr': subcommands.AddrCommand, 'buckets': subcommands.BucketsCommand, 'cat': subcommands.CatCommand, 'csv': subcommands.CSVCommand, diff --git a/tools/deep_memory_profiler/subcommands/__init__.py b/tools/deep_memory_profiler/subcommands/__init__.py index 4fb29d0..cc28dfd 100644 --- a/tools/deep_memory_profiler/subcommands/__init__.py +++ b/tools/deep_memory_profiler/subcommands/__init__.py @@ -2,6 +2,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +from subcommands.addr import AddrCommand from subcommands.buckets import BucketsCommand from subcommands.cat import CatCommand from subcommands.expand import ExpandCommand diff --git a/tools/deep_memory_profiler/subcommands/addr.py b/tools/deep_memory_profiler/subcommands/addr.py new file mode 100644 index 0000000..ee399e8 --- /dev/null +++ b/tools/deep_memory_profiler/subcommands/addr.py @@ -0,0 +1,88 @@ +# Copyright 2013 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import logging +import sys +import re + +from lib.subcommand import SubCommand + + +LOGGER = logging.getLogger('dmprof') + + +class AddrCommand(SubCommand): + def __init__(self): + super(AddrCommand, self).__init__('Usage: %prog addr ') + + def do(self, sys_argv, out=sys.stdout): + _, args = self._parse_args(sys_argv, 1) + dump_path = args[1] + (bucket_set, dump) = SubCommand.load_basic_files(dump_path, False) + AddrCommand._output(dump, bucket_set, out) + return 0 + + @staticmethod + def _output(dump, bucket_set, out): + """Prints memory usage by function addresses with resolving symbols. + + Args: + bucket_set: A BucketSet object. + out: An IO object to output. + """ + sizes = {} + library = {} + + _ADDR_PATTERN = re.compile(r'^0x[a-f0-9]+$', re.IGNORECASE) + _TCMALLOC_PATTERN = re.compile(r'.*(ProfilerMalloc|MemoryRegionMap::' + '|TypeProfilerMalloc|DoAllocWithArena|SbrkSysAllocator::Alloc' + '|MmapSysAllocator::Alloc|LowLevelAlloc::Alloc' + '|LowLevelAlloc::AllocWithArena).*', re.IGNORECASE) + + for bucket_id, virtual, committed, _, _ in dump.iter_stacktrace: + bucket = bucket_set.get(bucket_id) + if not bucket: + AddrCommand._add_size(bucket_id, "bucket", virtual, committed, sizes) + continue + + if _TCMALLOC_PATTERN.match(bucket.symbolized_joined_stackfunction): + AddrCommand._add_size("TCMALLOC", "TCMALLOC", + virtual, committed, sizes) + continue + + for index, addr in enumerate(bucket.stacktrace): + if _ADDR_PATTERN.match(bucket.symbolized_stackfunction[index]): + AddrCommand._find_library(addr, dump, library) + AddrCommand._add_size(hex(addr), library[addr], + virtual, committed, sizes) + else: + AddrCommand._add_size(hex(addr), + bucket.symbolized_stackfunction[index] + + "@" + bucket.symbolized_stacksourcefile[index], + virtual, committed, sizes) + + for key in sorted(sizes): + out.write('%s;%s;%s;%s\n' % (sizes[key]["vss"], sizes[key]["rss"], + key, sizes[key]["desc"])) + + + @staticmethod + def _add_size(key, desc, vss, rss, sizes): + if not key in sizes: + sizes[key] = {"desc":desc, "vss":0, "rss":0, "alloc":0, "free": 0} + if sizes[key]["desc"] == desc: + sizes[key]["vss"] += vss + sizes[key]["rss"] += rss + else: + sys.stderr.write('%s:(%s) or (%s)?\n' % (key, sizes[key]["desc"], desc)) + sys.exit(1) + + @staticmethod + def _find_library(func, dump, library): + if not func in library: + library[func] = "Unknown" + for addr, region in dump.iter_map: + if addr[0] >= func and func < addr[1]: + library[func] = region[1]['vma']['name'] + break \ No newline at end of file -- cgit v1.1