Fix import error in mac_platform_backend.py
[chromium-blink-merge.git] / tools / deep_memory_profiler / lib / bucket.py
blob51af5b2ddd82bc18f1420c4202fa80f5f039f754
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.
5 import logging
6 import os
8 from lib.symbol import FUNCTION_SYMBOLS, SOURCEFILE_SYMBOLS, TYPEINFO_SYMBOLS
11 LOGGER = logging.getLogger('dmprof')
13 # Indexes in dumped heap profile dumps.
14 VIRTUAL, COMMITTED, ALLOC_COUNT, FREE_COUNT, _, BUCKET_ID = range(6)
17 class Bucket(object):
18 """Represents a bucket, which is a unit of memory block classification."""
20 def __init__(self, stacktrace, allocator_type, typeinfo, typeinfo_name):
21 self._stacktrace = stacktrace
22 self._allocator_type = allocator_type
23 self._typeinfo = typeinfo
24 self._typeinfo_name = typeinfo_name
26 self._symbolized_stackfunction = stacktrace
27 self._symbolized_joined_stackfunction = ''
28 self._symbolized_stacksourcefile = stacktrace
29 self._symbolized_joined_stacksourcefile = ''
30 self._symbolized_typeinfo = typeinfo_name
32 self.component_cache = ''
34 def __str__(self):
35 result = []
36 result.append(self._allocator_type)
37 if self._symbolized_typeinfo == 'no typeinfo':
38 result.append('tno_typeinfo')
39 else:
40 result.append('t' + self._symbolized_typeinfo)
41 result.append('n' + self._typeinfo_name)
42 result.extend(['%s(@%s)' % (function, sourcefile)
43 for function, sourcefile
44 in zip(self._symbolized_stackfunction,
45 self._symbolized_stacksourcefile)])
46 return ' '.join(result)
48 def symbolize(self, symbol_mapping_cache):
49 """Makes a symbolized stacktrace and typeinfo with |symbol_mapping_cache|.
51 Args:
52 symbol_mapping_cache: A SymbolMappingCache object.
53 """
54 # TODO(dmikurube): Fill explicitly with numbers if symbol not found.
55 self._symbolized_stackfunction = [
56 symbol_mapping_cache.lookup(FUNCTION_SYMBOLS, address)
57 for address in self._stacktrace]
58 self._symbolized_joined_stackfunction = ' '.join(
59 self._symbolized_stackfunction)
60 self._symbolized_stacksourcefile = [
61 symbol_mapping_cache.lookup(SOURCEFILE_SYMBOLS, address)
62 for address in self._stacktrace]
63 self._symbolized_joined_stacksourcefile = ' '.join(
64 self._symbolized_stacksourcefile)
65 if not self._typeinfo:
66 self._symbolized_typeinfo = 'no typeinfo'
67 else:
68 self._symbolized_typeinfo = symbol_mapping_cache.lookup(
69 TYPEINFO_SYMBOLS, self._typeinfo)
70 if not self._symbolized_typeinfo:
71 self._symbolized_typeinfo = 'no typeinfo'
73 def clear_component_cache(self):
74 self.component_cache = ''
76 @property
77 def stacktrace(self):
78 return self._stacktrace
80 @property
81 def allocator_type(self):
82 return self._allocator_type
84 @property
85 def typeinfo(self):
86 return self._typeinfo
88 @property
89 def typeinfo_name(self):
90 return self._typeinfo_name
92 @property
93 def symbolized_stackfunction(self):
94 return self._symbolized_stackfunction
96 @property
97 def symbolized_joined_stackfunction(self):
98 return self._symbolized_joined_stackfunction
100 @property
101 def symbolized_stacksourcefile(self):
102 return self._symbolized_stacksourcefile
104 @property
105 def symbolized_joined_stacksourcefile(self):
106 return self._symbolized_joined_stacksourcefile
108 @property
109 def symbolized_typeinfo(self):
110 return self._symbolized_typeinfo
113 class BucketSet(object):
114 """Represents a set of bucket."""
115 def __init__(self):
116 self._buckets = {}
117 self._code_addresses = set()
118 self._typeinfo_addresses = set()
120 def load(self, prefix):
121 """Loads all related bucket files.
123 Args:
124 prefix: A prefix string for bucket file names.
126 LOGGER.info('Loading bucket files.')
128 n = 0
129 skipped = 0
130 while True:
131 path = '%s.%04d.buckets' % (prefix, n)
132 if not os.path.exists(path) or not os.stat(path).st_size:
133 if skipped > 10:
134 break
135 n += 1
136 skipped += 1
137 continue
138 LOGGER.info(' %s' % path)
139 with open(path, 'r') as f:
140 self._load_file(f)
141 n += 1
142 skipped = 0
144 def _load_file(self, bucket_f):
145 for line in bucket_f:
146 words = line.split()
147 typeinfo = None
148 typeinfo_name = ''
149 stacktrace_begin = 2
150 for index, word in enumerate(words):
151 if index < 2:
152 continue
153 if word[0] == 't':
154 typeinfo = int(word[1:], 16)
155 self._typeinfo_addresses.add(typeinfo)
156 elif word[0] == 'n':
157 typeinfo_name = word[1:]
158 else:
159 stacktrace_begin = index
160 break
161 stacktrace = [int(address, 16) for address in words[stacktrace_begin:]]
162 for frame in stacktrace:
163 self._code_addresses.add(frame)
164 self._buckets[int(words[0])] = Bucket(
165 stacktrace, words[1], typeinfo, typeinfo_name)
167 def __iter__(self):
168 for bucket_id, bucket_content in self._buckets.iteritems():
169 yield bucket_id, bucket_content
171 def __getitem__(self, bucket_id):
172 return self._buckets[bucket_id]
174 def get(self, bucket_id):
175 return self._buckets.get(bucket_id)
177 def symbolize(self, symbol_mapping_cache):
178 for bucket_content in self._buckets.itervalues():
179 bucket_content.symbolize(symbol_mapping_cache)
181 def clear_component_cache(self):
182 for bucket_content in self._buckets.itervalues():
183 bucket_content.clear_component_cache()
185 def iter_addresses(self, symbol_type):
186 if symbol_type in [FUNCTION_SYMBOLS, SOURCEFILE_SYMBOLS]:
187 for function in self._code_addresses:
188 yield function
189 else:
190 for function in self._typeinfo_addresses:
191 yield function