17dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch# Copyright 2013 The Chromium Authors. All rights reserved. 27dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch# Use of this source code is governed by a BSD-style license that can be 37dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch# found in the LICENSE file. 47dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 57dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochimport logging 67dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochimport sys 77dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 87dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochfrom lib.bucket import BUCKET_ID, COMMITTED, ALLOC_COUNT, FREE_COUNT 97dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochfrom lib.policy import PolicySet 107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochfrom lib.subcommand import SubCommand 117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 137dbb3d5cf0c15f500944d211057644d6a2f37371Ben MurdochLOGGER = logging.getLogger('dmprof') 147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochclass ExpandCommand(SubCommand): 177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch def __init__(self): 187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch super(ExpandCommand, self).__init__( 197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 'Usage: %prog expand <dump> <policy> <component> <depth>') 205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self._parser.add_option('--alternative-dirs', dest='alternative_dirs', 215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) metavar='/path/on/target@/path/on/host[:...]', 225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) help='Read files in /path/on/host/ instead of ' 235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 'files in /path/on/target/.') 247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch def do(self, sys_argv): 265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) options, args = self._parse_args(sys_argv, 4) 277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch dump_path = args[1] 287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch target_policy = args[2] 297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch component_name = args[3] 307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch depth = args[4] 315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) alternative_dirs_dict = {} 325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch policy_set = PolicySet.load(SubCommand._parse_policy_list(target_policy)) 345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if not policy_set[target_policy].find_rule(component_name): 355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) sys.stderr.write("ERROR: Component %s not found in policy %s\n" 365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) % (component_name, target_policy)) 375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return 1 385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if options.alternative_dirs: 405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for alternative_dir_pair in options.alternative_dirs.split(':'): 415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) target_path, host_path = alternative_dir_pair.split('@', 1) 425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) alternative_dirs_dict[target_path] = host_path 435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) (bucket_set, dump) = SubCommand.load_basic_files( 445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) dump_path, False, alternative_dirs=alternative_dirs_dict) 457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch ExpandCommand._output(dump, policy_set[target_policy], bucket_set, 477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch component_name, int(depth), sys.stdout) 487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch return 0 497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch @staticmethod 517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch def _output(dump, policy, bucket_set, component_name, depth, out): 527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch """Prints all stacktraces in a given component of given depth. 537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch Args: 557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch dump: A Dump object. 567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch policy: A Policy object. 577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch bucket_set: A BucketSet object. 587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch component_name: A name of component for filtering. 597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch depth: An integer representing depth to be printed. 607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch out: An IO object to output. 617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch """ 627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch sizes = {} 637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch ExpandCommand._accumulate( 657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch dump, policy, bucket_set, component_name, depth, sizes) 667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch sorted_sizes_list = sorted( 687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch sizes.iteritems(), key=(lambda x: x[1]), reverse=True) 697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch total = 0 707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch # TODO(dmikurube): Better formatting. 717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch for size_pair in sorted_sizes_list: 727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch out.write('%10d %s\n' % (size_pair[1], size_pair[0])) 737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch total += size_pair[1] 747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch LOGGER.info('total: %d\n' % total) 757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch @staticmethod 777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch def _add_size(precedence, bucket, depth, committed, sizes): 787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch stacktrace_sequence = precedence 797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch for function, sourcefile in zip( 807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch bucket.symbolized_stackfunction[ 817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 0 : min(len(bucket.symbolized_stackfunction), 1 + depth)], 827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch bucket.symbolized_stacksourcefile[ 837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 0 : min(len(bucket.symbolized_stacksourcefile), 1 + depth)]): 847dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch stacktrace_sequence += '%s(@%s) ' % (function, sourcefile) 857dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if not stacktrace_sequence in sizes: 867dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch sizes[stacktrace_sequence] = 0 877dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch sizes[stacktrace_sequence] += committed 887dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 897dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch @staticmethod 907dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch def _accumulate(dump, policy, bucket_set, component_name, depth, sizes): 917dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch rule = policy.find_rule(component_name) 927dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if not rule: 937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch pass 947dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch elif rule.allocator_type == 'malloc': 957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch for line in dump.iter_stacktrace: 967dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch words = line.split() 977dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch bucket = bucket_set.get(int(words[BUCKET_ID])) 987dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if not bucket or bucket.allocator_type == 'malloc': 997dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch component_match = policy.find_malloc(bucket) 1007dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch elif bucket.allocator_type == 'mmap': 1017dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch continue 1027dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch else: 1037dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch assert False 1047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if component_match == component_name: 1057dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch precedence = '' 1067dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch precedence += '(alloc=%d) ' % int(words[ALLOC_COUNT]) 1077dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch precedence += '(free=%d) ' % int(words[FREE_COUNT]) 1087dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if bucket.typeinfo: 1097dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch precedence += '(type=%s) ' % bucket.symbolized_typeinfo 1107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch precedence += '(type.name=%s) ' % bucket.typeinfo_name 1117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch ExpandCommand._add_size(precedence, bucket, depth, 1127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch int(words[COMMITTED]), sizes) 1137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch elif rule.allocator_type == 'mmap': 1147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch for _, region in dump.iter_map: 1157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if region[0] != 'hooked': 1167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch continue 1177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch component_match, bucket = policy.find_mmap(region, bucket_set) 1187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if component_match == component_name: 1197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch ExpandCommand._add_size('', bucket, depth, 1207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch region[1]['committed'], sizes) 121