Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 # Copyright 2013 The Chromium Authors. All rights reserved. | |
| 2 # Use of this source code is governed by a BSD-style license that can be | |
| 3 # found in the LICENSE file. | |
| 4 | |
| 5 import logging | |
| 6 import os | |
| 7 | |
| 8 from lib.symbol import FUNCTION_SYMBOLS, SOURCEFILE_SYMBOLS, TYPEINFO_SYMBOLS | |
| 9 | |
| 10 | |
| 11 LOGGER = logging.getLogger('dmprof') | |
| 12 | |
| 13 # Indexes in dumped heap profile dumps. | |
| 14 BUCKET_ID = 5 | |
|
peria
2013/07/16 11:50:32
If all constant numbers are indexes, they should b
M-A Ruel
2013/07/16 13:31:32
In general, I use the following idiom:
VIRTUAL, C
Dai Mikurube (NOT FULLTIME)
2013/07/17 05:55:06
Good catch. Thanks.
The index is applied for resu
| |
| 15 VIRTUAL = 0 | |
| 16 COMMITTED = 1 | |
| 17 ALLOC_COUNT = 2 | |
| 18 FREE_COUNT = 3 | |
| 19 | |
| 20 | |
| 21 class Bucket(object): | |
| 22 """Represents a bucket, which is a unit of memory block classification.""" | |
| 23 | |
| 24 def __init__(self, stacktrace, allocator_type, typeinfo, typeinfo_name): | |
| 25 self._stacktrace = stacktrace | |
| 26 self._allocator_type = allocator_type | |
| 27 self._typeinfo = typeinfo | |
| 28 self._typeinfo_name = typeinfo_name | |
| 29 | |
| 30 self._symbolized_stackfunction = stacktrace | |
| 31 self._symbolized_joined_stackfunction = '' | |
| 32 self._symbolized_stacksourcefile = stacktrace | |
| 33 self._symbolized_joined_stacksourcefile = '' | |
| 34 self._symbolized_typeinfo = typeinfo_name | |
| 35 | |
| 36 self.component_cache = '' | |
| 37 | |
| 38 def __str__(self): | |
| 39 result = [] | |
| 40 result.append(self._allocator_type) | |
| 41 if self._symbolized_typeinfo == 'no typeinfo': | |
| 42 result.append('tno_typeinfo') | |
| 43 else: | |
| 44 result.append('t' + self._symbolized_typeinfo) | |
| 45 result.append('n' + self._typeinfo_name) | |
| 46 result.extend(['%s(@%s)' % (function, sourcefile) | |
| 47 for function, sourcefile | |
| 48 in zip(self._symbolized_stackfunction, | |
| 49 self._symbolized_stacksourcefile)]) | |
| 50 return ' '.join(result) | |
| 51 | |
| 52 def symbolize(self, symbol_mapping_cache): | |
| 53 """Makes a symbolized stacktrace and typeinfo with |symbol_mapping_cache|. | |
| 54 | |
| 55 Args: | |
| 56 symbol_mapping_cache: A SymbolMappingCache object. | |
| 57 """ | |
| 58 # TODO(dmikurube): Fill explicitly with numbers if symbol not found. | |
| 59 self._symbolized_stackfunction = [ | |
| 60 symbol_mapping_cache.lookup(FUNCTION_SYMBOLS, address) | |
| 61 for address in self._stacktrace] | |
| 62 self._symbolized_joined_stackfunction = ' '.join( | |
| 63 self._symbolized_stackfunction) | |
| 64 self._symbolized_stacksourcefile = [ | |
| 65 symbol_mapping_cache.lookup(SOURCEFILE_SYMBOLS, address) | |
| 66 for address in self._stacktrace] | |
| 67 self._symbolized_joined_stacksourcefile = ' '.join( | |
| 68 self._symbolized_stacksourcefile) | |
| 69 if not self._typeinfo: | |
| 70 self._symbolized_typeinfo = 'no typeinfo' | |
| 71 else: | |
| 72 self._symbolized_typeinfo = symbol_mapping_cache.lookup( | |
| 73 TYPEINFO_SYMBOLS, self._typeinfo) | |
| 74 if not self._symbolized_typeinfo: | |
| 75 self._symbolized_typeinfo = 'no typeinfo' | |
| 76 | |
| 77 def clear_component_cache(self): | |
| 78 self.component_cache = '' | |
| 79 | |
| 80 @property | |
| 81 def stacktrace(self): | |
| 82 return self._stacktrace | |
| 83 | |
| 84 @property | |
| 85 def allocator_type(self): | |
| 86 return self._allocator_type | |
| 87 | |
| 88 @property | |
| 89 def typeinfo(self): | |
| 90 return self._typeinfo | |
| 91 | |
| 92 @property | |
| 93 def typeinfo_name(self): | |
| 94 return self._typeinfo_name | |
| 95 | |
| 96 @property | |
| 97 def symbolized_stackfunction(self): | |
| 98 return self._symbolized_stackfunction | |
| 99 | |
| 100 @property | |
| 101 def symbolized_joined_stackfunction(self): | |
| 102 return self._symbolized_joined_stackfunction | |
| 103 | |
| 104 @property | |
| 105 def symbolized_stacksourcefile(self): | |
| 106 return self._symbolized_stacksourcefile | |
| 107 | |
| 108 @property | |
| 109 def symbolized_joined_stacksourcefile(self): | |
| 110 return self._symbolized_joined_stacksourcefile | |
| 111 | |
| 112 @property | |
| 113 def symbolized_typeinfo(self): | |
| 114 return self._symbolized_typeinfo | |
| 115 | |
| 116 | |
| 117 class BucketSet(object): | |
| 118 """Represents a set of bucket.""" | |
| 119 def __init__(self): | |
| 120 self._buckets = {} | |
| 121 self._code_addresses = set() | |
| 122 self._typeinfo_addresses = set() | |
| 123 | |
| 124 def load(self, prefix): | |
| 125 """Loads all related bucket files. | |
| 126 | |
| 127 Args: | |
| 128 prefix: A prefix string for bucket file names. | |
| 129 """ | |
| 130 LOGGER.info('Loading bucket files.') | |
| 131 | |
| 132 n = 0 | |
| 133 skipped = 0 | |
| 134 while True: | |
| 135 path = '%s.%04d.buckets' % (prefix, n) | |
| 136 if not os.path.exists(path) or not os.stat(path).st_size: | |
| 137 if skipped > 10: | |
| 138 break | |
| 139 n += 1 | |
| 140 skipped += 1 | |
| 141 continue | |
| 142 LOGGER.info(' %s' % path) | |
| 143 with open(path, 'r') as f: | |
| 144 self._load_file(f) | |
| 145 n += 1 | |
| 146 skipped = 0 | |
| 147 | |
| 148 def _load_file(self, bucket_f): | |
| 149 for line in bucket_f: | |
| 150 words = line.split() | |
| 151 typeinfo = None | |
| 152 typeinfo_name = '' | |
| 153 stacktrace_begin = 2 | |
| 154 for index, word in enumerate(words): | |
| 155 if index < 2: | |
| 156 continue | |
| 157 if word[0] == 't': | |
| 158 typeinfo = int(word[1:], 16) | |
| 159 self._typeinfo_addresses.add(typeinfo) | |
| 160 elif word[0] == 'n': | |
| 161 typeinfo_name = word[1:] | |
| 162 else: | |
| 163 stacktrace_begin = index | |
| 164 break | |
| 165 stacktrace = [int(address, 16) for address in words[stacktrace_begin:]] | |
| 166 for frame in stacktrace: | |
| 167 self._code_addresses.add(frame) | |
| 168 self._buckets[int(words[0])] = Bucket( | |
| 169 stacktrace, words[1], typeinfo, typeinfo_name) | |
| 170 | |
| 171 def __iter__(self): | |
| 172 for bucket_id, bucket_content in self._buckets.iteritems(): | |
| 173 yield bucket_id, bucket_content | |
| 174 | |
| 175 def __getitem__(self, bucket_id): | |
| 176 return self._buckets[bucket_id] | |
| 177 | |
| 178 def get(self, bucket_id): | |
| 179 return self._buckets.get(bucket_id) | |
| 180 | |
| 181 def symbolize(self, symbol_mapping_cache): | |
| 182 for bucket_content in self._buckets.itervalues(): | |
| 183 bucket_content.symbolize(symbol_mapping_cache) | |
| 184 | |
| 185 def clear_component_cache(self): | |
| 186 for bucket_content in self._buckets.itervalues(): | |
| 187 bucket_content.clear_component_cache() | |
| 188 | |
| 189 def iter_addresses(self, symbol_type): | |
| 190 if symbol_type in [FUNCTION_SYMBOLS, SOURCEFILE_SYMBOLS]: | |
| 191 for function in self._code_addresses: | |
| 192 yield function | |
| 193 else: | |
| 194 for function in self._typeinfo_addresses: | |
| 195 yield function | |
| OLD | NEW |