| Index: tools/deep_memory_profiler/dmprof
|
| diff --git a/tools/deep_memory_profiler/dmprof b/tools/deep_memory_profiler/dmprof
|
| index 74b2c77b7f6b250e421694fea62ac140d98f92ae..f7ae0e4dfe8064009c98239e1009e61ac21376cc 100755
|
| --- a/tools/deep_memory_profiler/dmprof
|
| +++ b/tools/deep_memory_profiler/dmprof
|
| @@ -21,8 +21,9 @@ FIND_RUNTIME_SYMBOLS_PATH = os.path.join(
|
| 'find_runtime_symbols')
|
| sys.path.append(FIND_RUNTIME_SYMBOLS_PATH)
|
|
|
| -from prepare_symbol_info import prepare_symbol_info
|
| from find_runtime_symbols import find_runtime_symbols_list
|
| +from prepare_symbol_info import prepare_symbol_info
|
| +from static_symbols import StaticSymbols
|
|
|
| BUCKET_ID = 5
|
| VIRTUAL = 0
|
| @@ -106,6 +107,29 @@ class ObsoleteDumpVersionException(ParsingException):
|
| return "obsolete heap profile dump version: %s" % repr(self.value)
|
|
|
|
|
| +class DelayedStaticSymbols(object):
|
| + """Represents static symbol information loaded lazily."""
|
| +
|
| + def __init__(self, prefix, keep=False):
|
| + self.maps_path = prefix + '.maps'
|
| + self.keep = keep
|
| + if keep:
|
| + self.prepared_data_dir = prefix + '.pre'
|
| + self.loaded_static_symbols = None
|
| +
|
| + def get(self):
|
| + if not self.loaded_static_symbols:
|
| + if not self.keep:
|
| + self.prepared_data_dir = tempfile.mkdtemp()
|
| + try:
|
| + prepare_symbol_info(self.maps_path, self.prepared_data_dir)
|
| + self.loaded_static_symbols = StaticSymbols.load(self.prepared_data_dir)
|
| + finally:
|
| + if not self.keep:
|
| + shutil.rmtree(self.prepared_data_dir)
|
| + return self.loaded_static_symbols
|
| +
|
| +
|
| class Rule(object):
|
| """Represents one matching rule in a policy file."""
|
|
|
| @@ -192,7 +216,7 @@ class Dump(object):
|
| for i in range(0, BUCKET_ID - 1):
|
| sys.stdout.write(words[i] + ' ')
|
| for address in bucket.stacktrace:
|
| - sys.stdout.write((symbols.get(address) or address) + ' ')
|
| + sys.stdout.write((symbols.get(address) or ('0x%016x' % address)) + ' ')
|
| sys.stdout.write('\n')
|
|
|
| @staticmethod
|
| @@ -252,7 +276,7 @@ class Dump(object):
|
| int(words[ALLOC_COUNT]) - int(words[FREE_COUNT]),
|
| words[COMMITTED]))
|
| for address in bucket.stacktrace:
|
| - sys.stdout.write(' ' + address)
|
| + sys.stdout.write(' 0x%016x' % address)
|
| sys.stdout.write('\n')
|
|
|
| def print_for_pprof(
|
| @@ -576,7 +600,7 @@ class Dump(object):
|
|
|
|
|
| def update_symbols(
|
| - symbol_path, maps_path, appeared_addresses, symbols):
|
| + symbol_path, delayed_static_symbols, appeared_addresses, symbols):
|
| """Updates address/symbol mapping on memory and in a .symbol cache file.
|
|
|
| It reads cached address/symbol mapping from a .symbol file if it exists.
|
| @@ -591,7 +615,7 @@ def update_symbols(
|
|
|
| Args:
|
| symbol_path: A string representing a path for a .symbol file.
|
| - maps_path: A string of the path of /proc/.../maps.
|
| + delayed_static_symbols: A DelayedStaticSymbols object.
|
| appeared_addresses: A list of known addresses.
|
| symbols: A dict mapping runtime addresses to symbol names.
|
| """
|
| @@ -602,7 +626,7 @@ def update_symbols(
|
| items = line.split(None, 1)
|
| if len(items) == 1:
|
| items.append('??')
|
| - symbols[items[0]] = items[1].rstrip()
|
| + symbols[int(items[0], 16)] = items[1].rstrip()
|
| if symbols:
|
| sys.stderr.write(' Found %d symbols in cache.\n' % len(symbols))
|
| else:
|
| @@ -614,23 +638,20 @@ def update_symbols(
|
| if not unresolved_addresses:
|
| sys.stderr.write(' No need to resolve any more addresses.\n')
|
| else:
|
| - sys.stderr.write(' %d addresses are unresolved.\n' %
|
| + sys.stderr.write(' %d addresses unresolved.\n' %
|
| len(unresolved_addresses))
|
| - prepared_data_dir = tempfile.mkdtemp()
|
| - try:
|
| - prepare_symbol_info(maps_path, prepared_data_dir)
|
| + static_symbols = delayed_static_symbols.get()
|
| + symbol_list = find_runtime_symbols_list(
|
| + static_symbols, unresolved_addresses)
|
|
|
| - symbol_list = find_runtime_symbols_list(
|
| - prepared_data_dir, unresolved_addresses)
|
| + for address, symbol in zip(unresolved_addresses, symbol_list):
|
| + if not symbol:
|
| + symbol = '??'
|
| + stripped_symbol = symbol.strip()
|
| + symbols[address] = stripped_symbol
|
| + symbol_f.write('%x %s\n' % (address, stripped_symbol))
|
|
|
| - for address, symbol in zip(unresolved_addresses, symbol_list):
|
| - if not symbol:
|
| - symbol = '??'
|
| - stripped_symbol = symbol.strip()
|
| - symbols[address] = stripped_symbol
|
| - symbol_f.write('%s %s\n' % (address, stripped_symbol))
|
| - finally:
|
| - shutil.rmtree(prepared_data_dir)
|
| + sys.stderr.write(' All symbols resolved.\n')
|
|
|
|
|
| def parse_policy(policy_path):
|
| @@ -704,7 +725,8 @@ def load_buckets(prefix):
|
| with open(buckets_path, 'r') as buckets_f:
|
| for line in buckets_f:
|
| words = line.split()
|
| - buckets[int(words[0])] = Bucket(words[2:], words[1] == 'mmap')
|
| + stacktrace = [int(address, 16) for address in words[2:]]
|
| + buckets[int(words[0])] = Bucket(stacktrace, words[1] == 'mmap')
|
| n += 1
|
|
|
| return buckets
|
| @@ -761,12 +783,13 @@ def load_dumps(dump_path_list, buckets):
|
| return dumps, appeared_addresses
|
|
|
|
|
| -def load_and_update_symbol_cache(prefix, appeared_addresses):
|
| - maps_path = prefix + '.maps'
|
| +def load_and_update_symbol_cache(
|
| + prefix, appeared_addresses, delayed_static_symbols):
|
| symbol_path = prefix + '.symbols'
|
| sys.stderr.write('Loading and updating symbol cache: "%s".\n' % symbol_path)
|
| symbols = {}
|
| - update_symbols(symbol_path, maps_path, appeared_addresses, symbols)
|
| + update_symbols(
|
| + symbol_path, delayed_static_symbols, appeared_addresses, symbols)
|
| return symbols
|
|
|
|
|
| @@ -808,8 +831,31 @@ def load_policies(options_policy):
|
| return policies
|
|
|
|
|
| +def load_basic_files_with_multiple_dumps(dump_path, keep):
|
| + prefix = find_prefix(dump_path)
|
| + buckets = load_buckets(prefix)
|
| + dumps, appeared_addresses = load_dumps(
|
| + determine_dump_path_list(dump_path, prefix), buckets)
|
| + delayed_static_symbols = DelayedStaticSymbols(prefix, keep)
|
| + symbols = load_and_update_symbol_cache(
|
| + prefix, appeared_addresses, delayed_static_symbols)
|
| + return buckets, dumps, appeared_addresses, delayed_static_symbols, symbols
|
| +
|
| +
|
| +def load_basic_files_with_single_dump(dump_path, keep):
|
| + prefix = find_prefix(dump_path)
|
| + buckets = load_buckets(prefix)
|
| + dump, appeared_addresses = load_dump(dump_path, buckets)
|
| + delayed_static_symbols = DelayedStaticSymbols(prefix, keep)
|
| + symbols = load_and_update_symbol_cache(
|
| + prefix, appeared_addresses, delayed_static_symbols)
|
| + return buckets, dump, appeared_addresses, delayed_static_symbols, symbols
|
| +
|
| +
|
| def do_stacktrace(sys_argv):
|
| - parser = optparse.OptionParser(usage='Usage: %prog stacktrace <dump>')
|
| + parser = optparse.OptionParser(
|
| + 'Usage: %prog stacktrace [--keep] <dump>')
|
| + parser.add_option('--keep', dest='keep', action='store_true')
|
| options, args = parser.parse_args(sys_argv)
|
|
|
| if len(args) != 2:
|
| @@ -818,10 +864,8 @@ def do_stacktrace(sys_argv):
|
|
|
| dump_path = args[1]
|
|
|
| - prefix = find_prefix(dump_path)
|
| - buckets = load_buckets(prefix)
|
| - dump, appeared_addresses = load_dump(dump_path, buckets)
|
| - symbols = load_and_update_symbol_cache(prefix, appeared_addresses)
|
| + buckets, dump, appeared_addresses, delayed_static_symbols, symbols = (
|
| + load_basic_files_with_single_dump(dump_path, options.keep))
|
|
|
| dump.print_stacktrace(buckets, symbols)
|
|
|
| @@ -829,9 +873,11 @@ def do_stacktrace(sys_argv):
|
|
|
|
|
| def do_csv(sys_argv):
|
| - parser = optparse.OptionParser('Usage: %prog csv [-p POLICY] <first-dump>')
|
| + parser = optparse.OptionParser(
|
| + 'Usage: %prog csv [-p POLICY] [--keep] <first-dump>')
|
| parser.add_option('-p', '--policy', type='string', dest='policy',
|
| help='profile with POLICY', metavar='POLICY')
|
| + parser.add_option('--keep', dest='keep', action='store_true')
|
| options, args = parser.parse_args(sys_argv)
|
|
|
| if len(args) != 2:
|
| @@ -840,11 +886,8 @@ def do_csv(sys_argv):
|
|
|
| dump_path = args[1]
|
|
|
| - prefix = find_prefix(dump_path)
|
| - buckets = load_buckets(prefix)
|
| - dumps, appeared_addresses = load_dumps(
|
| - determine_dump_path_list(dump_path, prefix), buckets)
|
| - symbols = load_and_update_symbol_cache(prefix, appeared_addresses)
|
| + buckets, dumps, appeared_addresses, delayed_static_symbols, symbols = (
|
| + load_basic_files_with_multiple_dumps(dump_path, options.keep))
|
| policies = load_policies(options.policy)
|
|
|
| max_components = 0
|
| @@ -879,9 +922,11 @@ def do_csv(sys_argv):
|
|
|
|
|
| def do_json(sys_argv):
|
| - parser = optparse.OptionParser('Usage: %prog json [-p POLICY] <first-dump>')
|
| + parser = optparse.OptionParser(
|
| + 'Usage: %prog json [-p POLICY] [--keep] <first-dump>')
|
| parser.add_option('-p', '--policy', type='string', dest='policy',
|
| help='profile with POLICY', metavar='POLICY')
|
| + parser.add_option('--keep', dest='keep', action='store_true')
|
| options, args = parser.parse_args(sys_argv)
|
|
|
| if len(args) != 2:
|
| @@ -890,11 +935,8 @@ def do_json(sys_argv):
|
|
|
| dump_path = args[1]
|
|
|
| - prefix = find_prefix(dump_path)
|
| - buckets = load_buckets(prefix)
|
| - dumps, appeared_addresses = load_dumps(
|
| - determine_dump_path_list(dump_path, prefix), buckets)
|
| - symbols = load_and_update_symbol_cache(prefix, appeared_addresses)
|
| + buckets, dumps, appeared_addresses, delayed_static_symbols, symbols = (
|
| + load_basic_files_with_multiple_dumps(dump_path, options.keep))
|
| policies = load_policies(options.policy)
|
|
|
| json_base = {
|
| @@ -928,9 +970,11 @@ def do_json(sys_argv):
|
|
|
|
|
| def do_list(sys_argv):
|
| - parser = optparse.OptionParser('Usage: %prog [-p POLICY] list <first-dump>')
|
| + parser = optparse.OptionParser(
|
| + 'Usage: %prog [-p POLICY] [--keep] list <first-dump>')
|
| parser.add_option('-p', '--policy', type='string', dest='policy',
|
| help='profile with POLICY', metavar='POLICY')
|
| + parser.add_option('--keep', dest='keep', action='store_true')
|
| options, args = parser.parse_args(sys_argv)
|
|
|
| if len(args) != 2:
|
| @@ -939,11 +983,8 @@ def do_list(sys_argv):
|
|
|
| dump_path = args[1]
|
|
|
| - prefix = find_prefix(dump_path)
|
| - buckets = load_buckets(prefix)
|
| - dumps, appeared_addresses = load_dumps(
|
| - determine_dump_path_list(dump_path, prefix), buckets)
|
| - symbols = load_and_update_symbol_cache(prefix, appeared_addresses)
|
| + buckets, dumps, appeared_addresses, delayed_static_symbols, symbols = (
|
| + load_basic_files_with_multiple_dumps(dump_path, options.keep))
|
| policies = load_policies(options.policy)
|
|
|
| for policy in sorted(policies):
|
| @@ -968,7 +1009,8 @@ def do_list(sys_argv):
|
|
|
| def do_expand(sys_argv):
|
| parser = optparse.OptionParser(
|
| - 'Usage: %prog expand <dump> <policy> <component> <depth>')
|
| + 'Usage: %prog expand [--keep] <dump> <policy> <component> <depth>')
|
| + parser.add_option('--keep', dest='keep', action='store_true')
|
| options, args = parser.parse_args(sys_argv)
|
|
|
| if len(args) != 5:
|
| @@ -980,10 +1022,8 @@ def do_expand(sys_argv):
|
| component_name = args[3]
|
| depth = args[4]
|
|
|
| - prefix = find_prefix(dump_path)
|
| - buckets = load_buckets(prefix)
|
| - dump, appeared_addresses = load_dump(dump_path, buckets)
|
| - symbols = load_and_update_symbol_cache(prefix, appeared_addresses)
|
| + buckets, dump, appeared_addresses, delayed_static_symbols, symbols = (
|
| + load_basic_files_with_single_dump(dump_path, options.keep))
|
| policies = load_policies(target_policy)
|
|
|
| rule_list = policies[target_policy].rules
|
| @@ -995,9 +1035,10 @@ def do_expand(sys_argv):
|
|
|
| def do_pprof(sys_argv):
|
| parser = optparse.OptionParser(
|
| - 'Usage: %prog pprof [-c COMPONENT] <dump> <policy>')
|
| + 'Usage: %prog pprof [-c COMPONENT] [--keep] <dump> <policy>')
|
| parser.add_option('-c', '--component', type='string', dest='component',
|
| help='restrict to COMPONENT', metavar='COMPONENT')
|
| + parser.add_option('--keep', dest='keep', action='store_true')
|
| options, args = parser.parse_args(sys_argv)
|
|
|
| if len(args) != 3:
|
| @@ -1008,15 +1049,13 @@ def do_pprof(sys_argv):
|
| target_policy = args[2]
|
| component = options.component
|
|
|
| - prefix = find_prefix(dump_path)
|
| - buckets = load_buckets(prefix)
|
| - dump, appeared_addresses = load_dump(dump_path, buckets)
|
| - symbols = load_and_update_symbol_cache(prefix, appeared_addresses)
|
| + buckets, dump, appeared_addresses, delayed_static_symbols, symbols = (
|
| + load_basic_files_with_single_dump(dump_path, options.keep))
|
| policies = load_policies(target_policy)
|
|
|
| rule_list = policies[target_policy].rules
|
|
|
| - with open(prefix + '.maps', 'r') as maps_f:
|
| + with open(find_prefix(dump_path) + '.maps', 'r') as maps_f:
|
| maps_lines = maps_f.readlines()
|
| dump.print_for_pprof(rule_list, buckets, maps_lines, component, symbols)
|
|
|
| @@ -1055,12 +1094,12 @@ Commands:
|
| stacktrace Convert runtime addresses to symbol names
|
|
|
| Quick Reference:
|
| - dmprof csv [-p POLICY] <first-dump>
|
| - dmprof expand <dump> <policy> <component> <depth>
|
| - dmprof json [-p POLICY] <first-dump>
|
| - dmprof list [-p POLICY] <first-dump>
|
| - dmprof pprof [-c COMPONENT] <dump> <policy>
|
| - dmprof stacktrace <dump>
|
| + dmprof csv [-p POLICY] [--keep] <first-dump>
|
| + dmprof expand [--keep] <dump> <policy> <component> <depth>
|
| + dmprof json [-p POLICY] [--keep] <first-dump>
|
| + dmprof list [-p POLICY] [--keep] <first-dump>
|
| + dmprof pprof [-c COMPONENT] [--keep] <dump> <policy>
|
| + dmprof stacktrace [--keep] <dump>
|
| """ % (sys.argv[0]))
|
| sys.exit(1)
|
| action = sys.argv.pop(1)
|
|
|