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