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 os 77dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 87dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochfrom lib.symbol import FUNCTION_SYMBOLS, SOURCEFILE_SYMBOLS, TYPEINFO_SYMBOLS 97dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 117dbb3d5cf0c15f500944d211057644d6a2f37371Ben MurdochLOGGER = logging.getLogger('dmprof') 127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch# Indexes in dumped heap profile dumps. 147dbb3d5cf0c15f500944d211057644d6a2f37371Ben MurdochVIRTUAL, COMMITTED, ALLOC_COUNT, FREE_COUNT, _, BUCKET_ID = range(6) 157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochclass Bucket(object): 187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch """Represents a bucket, which is a unit of memory block classification.""" 197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch def __init__(self, stacktrace, allocator_type, typeinfo, typeinfo_name): 217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch self._stacktrace = stacktrace 227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch self._allocator_type = allocator_type 237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch self._typeinfo = typeinfo 247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch self._typeinfo_name = typeinfo_name 257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch self._symbolized_stackfunction = stacktrace 277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch self._symbolized_joined_stackfunction = '' 287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch self._symbolized_stacksourcefile = stacktrace 297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch self._symbolized_joined_stacksourcefile = '' 307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch self._symbolized_typeinfo = typeinfo_name 317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch self.component_cache = '' 337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch def __str__(self): 357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch result = [] 367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch result.append(self._allocator_type) 377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if self._symbolized_typeinfo == 'no typeinfo': 387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch result.append('tno_typeinfo') 397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch else: 407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch result.append('t' + self._symbolized_typeinfo) 417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch result.append('n' + self._typeinfo_name) 427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch result.extend(['%s(@%s)' % (function, sourcefile) 437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch for function, sourcefile 447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch in zip(self._symbolized_stackfunction, 457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch self._symbolized_stacksourcefile)]) 467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch return ' '.join(result) 477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch def symbolize(self, symbol_mapping_cache): 497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch """Makes a symbolized stacktrace and typeinfo with |symbol_mapping_cache|. 507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch Args: 527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch symbol_mapping_cache: A SymbolMappingCache object. 537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch """ 547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch # TODO(dmikurube): Fill explicitly with numbers if symbol not found. 557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch self._symbolized_stackfunction = [ 567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch symbol_mapping_cache.lookup(FUNCTION_SYMBOLS, address) 577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch for address in self._stacktrace] 587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch self._symbolized_joined_stackfunction = ' '.join( 597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch self._symbolized_stackfunction) 607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch self._symbolized_stacksourcefile = [ 617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch symbol_mapping_cache.lookup(SOURCEFILE_SYMBOLS, address) 627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch for address in self._stacktrace] 637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch self._symbolized_joined_stacksourcefile = ' '.join( 647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch self._symbolized_stacksourcefile) 657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if not self._typeinfo: 667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch self._symbolized_typeinfo = 'no typeinfo' 677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch else: 687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch self._symbolized_typeinfo = symbol_mapping_cache.lookup( 697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch TYPEINFO_SYMBOLS, self._typeinfo) 707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if not self._symbolized_typeinfo: 717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch self._symbolized_typeinfo = 'no typeinfo' 727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch def clear_component_cache(self): 747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch self.component_cache = '' 757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch @property 777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch def stacktrace(self): 787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch return self._stacktrace 797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch @property 817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch def allocator_type(self): 827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch return self._allocator_type 837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 847dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch @property 857dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch def typeinfo(self): 867dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch return self._typeinfo 877dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 887dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch @property 897dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch def typeinfo_name(self): 907dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch return self._typeinfo_name 917dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 927dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch @property 937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch def symbolized_stackfunction(self): 947dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch return self._symbolized_stackfunction 957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 967dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch @property 977dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch def symbolized_joined_stackfunction(self): 987dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch return self._symbolized_joined_stackfunction 997dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1007dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch @property 1017dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch def symbolized_stacksourcefile(self): 1027dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch return self._symbolized_stacksourcefile 1037dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch @property 1057dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch def symbolized_joined_stacksourcefile(self): 1067dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch return self._symbolized_joined_stacksourcefile 1077dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1087dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch @property 1097dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch def symbolized_typeinfo(self): 1107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch return self._symbolized_typeinfo 1117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochclass BucketSet(object): 1147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch """Represents a set of bucket.""" 1157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch def __init__(self): 1167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch self._buckets = {} 1177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch self._code_addresses = set() 1187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch self._typeinfo_addresses = set() 1197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch def load(self, prefix): 1217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch """Loads all related bucket files. 1227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch Args: 1247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch prefix: A prefix string for bucket file names. 1257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch """ 1267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch LOGGER.info('Loading bucket files.') 1277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch n = 0 1297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch skipped = 0 1307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch while True: 1317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch path = '%s.%04d.buckets' % (prefix, n) 1327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if not os.path.exists(path) or not os.stat(path).st_size: 1337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if skipped > 10: 1347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch break 1357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch n += 1 1367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch skipped += 1 1377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch continue 1387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch LOGGER.info(' %s' % path) 1397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch with open(path, 'r') as f: 1407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch self._load_file(f) 1417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch n += 1 1427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch skipped = 0 1437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch def _load_file(self, bucket_f): 1457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch for line in bucket_f: 1467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch words = line.split() 1477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch typeinfo = None 1487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch typeinfo_name = '' 1497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch stacktrace_begin = 2 1507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch for index, word in enumerate(words): 1517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if index < 2: 1527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch continue 1537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if word[0] == 't': 1547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch typeinfo = int(word[1:], 16) 1557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch self._typeinfo_addresses.add(typeinfo) 1567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch elif word[0] == 'n': 1577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch typeinfo_name = word[1:] 1587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch else: 1597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch stacktrace_begin = index 1607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch break 1617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch stacktrace = [int(address, 16) for address in words[stacktrace_begin:]] 1627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch for frame in stacktrace: 1637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch self._code_addresses.add(frame) 1647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch self._buckets[int(words[0])] = Bucket( 1657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch stacktrace, words[1], typeinfo, typeinfo_name) 1667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch def __iter__(self): 1687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch for bucket_id, bucket_content in self._buckets.iteritems(): 1697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch yield bucket_id, bucket_content 1707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch def __getitem__(self, bucket_id): 1727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch return self._buckets[bucket_id] 1737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch def get(self, bucket_id): 1757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch return self._buckets.get(bucket_id) 1767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch def symbolize(self, symbol_mapping_cache): 1787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch for bucket_content in self._buckets.itervalues(): 1797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch bucket_content.symbolize(symbol_mapping_cache) 1807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch def clear_component_cache(self): 1827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch for bucket_content in self._buckets.itervalues(): 1837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch bucket_content.clear_component_cache() 1847dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1857dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch def iter_addresses(self, symbol_type): 1867dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if symbol_type in [FUNCTION_SYMBOLS, SOURCEFILE_SYMBOLS]: 1877dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch for function in self._code_addresses: 1887dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch yield function 1897dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch else: 1907dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch for function in self._typeinfo_addresses: 1917dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch yield function 192