Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(101)

Side by Side Diff: tools/binary_size/libsupersize/models.py

Issue 2816093002: FREEZE.unindexed (Closed)
Patch Set: Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 # Copyright 2017 The Chromium Authors. All rights reserved. 1 # Copyright 2017 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 """Classes that comprise the data model for binary size analysis. 4 """Classes that comprise the data model for binary size analysis.
5 5
6 The primary classes are Symbol, and SymbolGroup. 6 The primary classes are Symbol, and SymbolGroup.
7 7
8 Description of common properties: 8 Description of common properties:
9 * address: The start address of the symbol. 9 * address: The start address of the symbol.
10 May be 0 (e.g. for .bss or for SymbolGroups). 10 May be 0 (e.g. for .bss or for SymbolGroups).
11 * size: The number of bytes this symbol takes up, including padding that comes 11 * size: The number of bytes this symbol takes up, including padding that comes
12 before |address|. 12 before |address|.
13 * num_aliases: The number of symbols with the same address (including self).
14 * pss: size / num_aliases.
13 * padding: The number of bytes of padding before |address| due to this symbol. 15 * padding: The number of bytes of padding before |address| due to this symbol.
14 * name: Symbol names with parameter list removed. 16 * name: Symbol names with parameter list removed.
15 Never None, but will be '' for anonymous symbols. 17 Never None, but will be '' for anonymous symbols.
16 * full_name: Symbols names with parameter list left in. 18 * full_name: Symbols names with parameter list left in.
17 Never None, but will be '' for anonymous symbols, and for symbols that do 19 Never None, but will be '' for anonymous symbols, and for symbols that do
18 not contain a parameter list. 20 not contain a parameter list.
19 * is_anonymous: True when the symbol exists in an anonymous namespace (which 21 * is_anonymous: True when the symbol exists in an anonymous namespace (which
20 are removed from both full_name and name during normalization). 22 are removed from both full_name and name during normalization).
21 * section_name: E.g. ".text", ".rodata", ".data.rel.local" 23 * section_name: E.g. ".text", ".rodata", ".data.rel.local"
22 * section: The second character of |section_name|. E.g. "t", "r", "d". 24 * section: The second character of |section_name|. E.g. "t", "r", "d".
23 """ 25 """
24 26
25 import collections 27 import collections
26 import copy 28 import copy
29 import logging
27 import os 30 import os
28 import re 31 import re
29 32
30 import match_util 33 import match_util
31 34
32 35
33 METADATA_GIT_REVISION = 'git_revision' 36 METADATA_GIT_REVISION = 'git_revision'
34 METADATA_APK_FILENAME = 'apk_file_name' # Path relative to output_directory. 37 METADATA_APK_FILENAME = 'apk_file_name' # Path relative to output_directory.
35 METADATA_MAP_FILENAME = 'map_file_name' # Path relative to output_directory. 38 METADATA_MAP_FILENAME = 'map_file_name' # Path relative to output_directory.
36 METADATA_ELF_ARCHITECTURE = 'elf_arch' # "Machine" field from readelf -h 39 METADATA_ELF_ARCHITECTURE = 'elf_arch' # "Machine" field from readelf -h
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
152 155
153 Refer to module docs for field descriptions. 156 Refer to module docs for field descriptions.
154 """ 157 """
155 158
156 __slots__ = ( 159 __slots__ = (
157 'address', 160 'address',
158 'full_name', 161 'full_name',
159 'is_anonymous', 162 'is_anonymous',
160 'object_path', 163 'object_path',
161 'name', 164 'name',
165 'num_aliases',
162 'padding', 166 'padding',
163 'section_name', 167 'section_name',
164 'source_path', 168 'source_path',
165 'size', 169 'size',
166 ) 170 )
167 171
168 def __init__(self, section_name, size_without_padding, address=None, 172 def __init__(self, section_name, size_without_padding, address=None,
169 name=None, source_path=None, object_path=None, 173 name=None, source_path=None, object_path=None,
170 full_name=None, is_anonymous=False): 174 full_name=None, is_anonymous=False, num_aliases=1):
171 self.section_name = section_name 175 self.section_name = section_name
172 self.address = address or 0 176 self.address = address or 0
173 self.name = name or '' 177 self.name = name or ''
174 self.full_name = full_name or '' 178 self.full_name = full_name or ''
175 self.source_path = source_path or '' 179 self.source_path = source_path or ''
176 self.object_path = object_path or '' 180 self.object_path = object_path or ''
177 self.size = size_without_padding 181 self.size = size_without_padding
178 # Change this to be a bitfield of flags if ever there is a need to add
179 # another similar thing.
180 self.is_anonymous = is_anonymous 182 self.is_anonymous = is_anonymous
183 self.num_aliases = num_aliases
181 self.padding = 0 184 self.padding = 0
182 185
183 def __repr__(self): 186 def __repr__(self):
184 return ('%s@%x(size_without_padding=%d,padding=%d,name=%s,path=%s,anon=%d)' 187 return ('%s@%x(size_without_padding=%d,padding=%d,name=%s,path=%s,anon=%d)'
185 % (self.section_name, self.address, self.size_without_padding, 188 % (self.section_name, self.address, self.size_without_padding,
186 self.padding, self.name, self.source_path or self.object_path, 189 self.padding, self.name, self.source_path or self.object_path,
187 int(self.is_anonymous))) 190 int(self.is_anonymous)))
188 191
192 @property
193 def pss(self):
194 return float(self.size) / self.num_aliases
195
196 @property
197 def pss_without_padding(self):
198 return float(self.size_without_padding) / self.num_aliases
199
189 200
190 class SymbolGroup(BaseSymbol): 201 class SymbolGroup(BaseSymbol):
191 """Represents a group of symbols using the same interface as Symbol. 202 """Represents a group of symbols using the same interface as Symbol.
192 203
193 SymbolGroups are immutable. All filtering / sorting will return new 204 SymbolGroups are immutable. All filtering / sorting will return new
194 SymbolGroups objects. 205 SymbolGroups objects.
195 206
196 Overrides many __functions__. E.g. the following are all valid: 207 Overrides many __functions__. E.g. the following are all valid:
197 * len(group) 208 * len(group)
198 * iter(group) 209 * iter(group)
199 * group[0] 210 * group[0]
200 * group['0x1234'] # By symbol address 211 * group['0x1234'] # By symbol address
201 * without_group2 = group1 - group2 212 * without_group2 = group1 - group2
202 * unioned = group1 + group2 213 * unioned = group1 + group2
203 """ 214 """
204 215
205 __slots__ = ( 216 __slots__ = (
206 '_padding', 217 '_padding',
207 '_size', 218 '_size',
219 '_pss',
208 '_symbols', 220 '_symbols',
209 '_filtered_symbols', 221 '_filtered_symbols',
210 'full_name', 222 'full_name',
211 'name', 223 'name',
212 'section_name', 224 'section_name',
213 'is_sorted', 225 'is_sorted',
214 ) 226 )
215 227
216 def __init__(self, symbols, filtered_symbols=None, name=None, 228 def __init__(self, symbols, filtered_symbols=None, name=None,
217 full_name=None, section_name=None, is_sorted=False): 229 full_name=None, section_name=None, is_sorted=False):
218 self._padding = None 230 self._padding = None
219 self._size = None 231 self._size = None
232 self._pss = None
220 self._symbols = symbols 233 self._symbols = symbols
221 self._filtered_symbols = filtered_symbols or [] 234 self._filtered_symbols = filtered_symbols or []
222 self.name = name or '' 235 self.name = name or ''
223 self.full_name = full_name 236 self.full_name = full_name
224 self.section_name = section_name or '.*' 237 self.section_name = section_name or '.*'
225 self.is_sorted = is_sorted 238 self.is_sorted = is_sorted
226 239
227 def __repr__(self): 240 def __repr__(self):
228 return 'Group(name=%s,count=%d,size=%d)' % ( 241 return 'Group(name=%s,count=%d,size=%d)' % (
229 self.name, len(self), self.size) 242 self.name, len(self), self.size)
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
270 283
271 @property 284 @property
272 def is_anonymous(self): 285 def is_anonymous(self):
273 first = self._symbols[0].is_anonymous 286 first = self._symbols[0].is_anonymous
274 return first if all( 287 return first if all(
275 s.is_anonymous == first for s in self._symbols) else False 288 s.is_anonymous == first for s in self._symbols) else False
276 289
277 @property 290 @property
278 def object_path(self): 291 def object_path(self):
279 first = self._symbols[0].object_path 292 first = self._symbols[0].object_path
280 return first if all(s.object_path == first for s in self._symbols) else None 293 return first if all(s.object_path == first for s in self._symbols) else ''
281 294
282 @property 295 @property
283 def source_path(self): 296 def source_path(self):
284 first = self._symbols[0].source_path 297 first = self._symbols[0].source_path
285 return first if all(s.source_path == first for s in self._symbols) else None 298 return first if all(s.source_path == first for s in self._symbols) else ''
299
300 def IterUniqueSymbols(self):
301 seen_addresses = set()
302 for s in self:
303 if s.num_aliases == 1:
304 yield s
305 elif s.address not in seen_addresses:
306 seen_addresses.add(s.address)
307 yield s
286 308
287 @property 309 @property
288 def size(self): 310 def size(self):
289 if self._size is None: 311 if self._size is None:
290 if self.IsBss(): 312 if self.IsBss():
291 self._size = sum(s.size for s in self) 313 self._size = sum(s.size for s in self)
292 self._size = sum(s.size for s in self if not s.IsBss()) 314 else:
315 self._size = sum(s.size for s in self.IterUniqueSymbols())
293 return self._size 316 return self._size
294 317
295 @property 318 @property
319 def pss(self):
320 if self._pss is None:
321 if self.IsBss():
322 self._pss = self.size
323 else:
324 self._pss = sum(s.pss for s in self)
325 return self._pss
326
327 @property
296 def padding(self): 328 def padding(self):
297 if self._padding is None: 329 if self._padding is None:
298 self._padding = sum(s.padding for s in self) 330 self._padding = sum(s.padding for s in self.IterUniqueSymbols())
299 return self._padding 331 return self._padding
300 332
333 @property
334 def num_aliases(self):
335 return 1
336
301 def IsGroup(self): 337 def IsGroup(self):
302 return True 338 return True
303 339
304 def _CreateTransformed(self, symbols, filtered_symbols=None, name=None, 340 def _CreateTransformed(self, symbols, filtered_symbols=None, name=None,
305 section_name=None, is_sorted=None): 341 section_name=None, is_sorted=None):
306 if is_sorted is None: 342 if is_sorted is None:
307 is_sorted = self.is_sorted 343 is_sorted = self.is_sorted
308 return SymbolGroup(symbols, filtered_symbols=filtered_symbols, name=name, 344 return SymbolGroup(symbols, filtered_symbols=filtered_symbols, name=name,
309 section_name=section_name, is_sorted=is_sorted) 345 section_name=section_name, is_sorted=is_sorted)
310 346
(...skipping 13 matching lines...) Expand all
324 360
325 def SortedByAddress(self, reverse=False): 361 def SortedByAddress(self, reverse=False):
326 return self.Sorted(key=(lambda s:s.address), reverse=reverse) 362 return self.Sorted(key=(lambda s:s.address), reverse=reverse)
327 363
328 def SortedByCount(self, reverse=False): 364 def SortedByCount(self, reverse=False):
329 return self.Sorted(key=(lambda s:len(s) if s.IsGroup() else 1), 365 return self.Sorted(key=(lambda s:len(s) if s.IsGroup() else 1),
330 reverse=not reverse) 366 reverse=not reverse)
331 367
332 def Filter(self, func): 368 def Filter(self, func):
333 filtered_and_kept = ([], []) 369 filtered_and_kept = ([], [])
334 for symbol in self: 370 symbol = None
335 filtered_and_kept[int(bool(func(symbol)))].append(symbol) 371 try:
372 for symbol in self:
373 filtered_and_kept[int(bool(func(symbol)))].append(symbol)
374 except:
375 logging.warning('Filter failed on symbol %r', symbol)
376 raise
377
336 return self._CreateTransformed(filtered_and_kept[1], 378 return self._CreateTransformed(filtered_and_kept[1],
337 filtered_symbols=filtered_and_kept[0], 379 filtered_symbols=filtered_and_kept[0],
338 section_name=self.section_name) 380 section_name=self.section_name)
339 381
340 def WhereBiggerThan(self, min_size): 382 def WhereBiggerThan(self, min_size):
341 return self.Filter(lambda s: s.size >= min_size) 383 return self.Filter(lambda s: s.size >= min_size)
342 384
343 def WhereInSection(self, section): 385 def WhereInSection(self, section):
344 if len(section) == 1: 386 if len(section) == 1:
345 ret = self.Filter(lambda s: s.section == section) 387 ret = self.Filter(lambda s: s.section == section)
(...skipping 335 matching lines...) Expand 10 before | Expand all | Expand 10 after
681 723
682 def _ExtractPrefixBeforeSeparator(string, separator, count=1): 724 def _ExtractPrefixBeforeSeparator(string, separator, count=1):
683 idx = -len(separator) 725 idx = -len(separator)
684 prev_idx = None 726 prev_idx = None
685 for _ in xrange(count): 727 for _ in xrange(count):
686 idx = string.find(separator, idx + len(separator)) 728 idx = string.find(separator, idx + len(separator))
687 if idx < 0: 729 if idx < 0:
688 break 730 break
689 prev_idx = idx 731 prev_idx = idx
690 return string[:prev_idx] 732 return string[:prev_idx]
OLDNEW
« no previous file with comments | « tools/binary_size/libsupersize/linker_map_parser.py ('k') | tools/binary_size/libsupersize/nm.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698