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

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

Issue 2864063002: Supersize: Chrome-specific breakdowns, console tweaks (Closed)
Patch Set: review tweaks Created 3 years, 7 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).
(...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after
326 @property 326 @property
327 def object_path(self): 327 def object_path(self):
328 first = self._symbols[0].object_path if self else '' 328 first = self._symbols[0].object_path if self else ''
329 return first if all(s.object_path == first for s in self._symbols) else '' 329 return first if all(s.object_path == first for s in self._symbols) else ''
330 330
331 @property 331 @property
332 def source_path(self): 332 def source_path(self):
333 first = self._symbols[0].source_path if self else '' 333 first = self._symbols[0].source_path if self else ''
334 return first if all(s.source_path == first for s in self._symbols) else '' 334 return first if all(s.source_path == first for s in self._symbols) else ''
335 335
336 def IterUniqueSymbols(self):
337 seen_aliases_lists = set()
338 for s in self:
339 if not s.aliases:
340 yield s
341 elif id(s.aliases) not in seen_aliases_lists:
342 seen_aliases_lists.add(id(s.aliases))
343 yield s
344
345 def CountUniqueSymbols(self):
346 return sum(1 for s in self.IterUniqueSymbols())
347
348 @property 336 @property
349 def size(self): 337 def size(self):
350 if self._size is None: 338 if self._size is None:
351 if self.IsBss(): 339 if self.IsBss():
352 self._size = sum(s.size for s in self) 340 self._size = sum(s.size for s in self)
353 else: 341 else:
354 self._size = sum(s.size for s in self.IterUniqueSymbols()) 342 self._size = sum(s.size for s in self.IterUniqueSymbols())
355 return self._size 343 return self._size
356 344
357 @property 345 @property
(...skipping 11 matching lines...) Expand all
369 self._padding = sum(s.padding for s in self.IterUniqueSymbols()) 357 self._padding = sum(s.padding for s in self.IterUniqueSymbols())
370 return self._padding 358 return self._padding
371 359
372 @property 360 @property
373 def aliases(self): 361 def aliases(self):
374 return None 362 return None
375 363
376 def IsGroup(self): 364 def IsGroup(self):
377 return True 365 return True
378 366
367 def IterUniqueSymbols(self):
368 """Yields all symbols, but only one from each alias group."""
369 seen_aliases_lists = set()
370 for s in self:
371 if not s.aliases:
372 yield s
373 elif id(s.aliases) not in seen_aliases_lists:
374 seen_aliases_lists.add(id(s.aliases))
375 yield s
376
377 def IterLeafSymbols(self):
378 """Yields all symbols, recursing into subgroups."""
379 for s in self:
380 if s.IsGroup():
381 for x in s.IterLeafSymbols():
382 yield x
383 else:
384 yield s
385
386 def CountUniqueSymbols(self):
387 return sum(1 for s in self.IterUniqueSymbols())
388
379 def _CreateTransformed(self, symbols, filtered_symbols=None, name=None, 389 def _CreateTransformed(self, symbols, filtered_symbols=None, name=None,
380 full_name=None, section_name=None, is_sorted=None): 390 full_name=None, section_name=None, is_sorted=None):
381 if is_sorted is None: 391 if is_sorted is None:
382 is_sorted = self.is_sorted 392 is_sorted = self.is_sorted
383 return SymbolGroup(symbols, filtered_symbols=filtered_symbols, name=name, 393 return SymbolGroup(symbols, filtered_symbols=filtered_symbols, name=name,
384 full_name=full_name, section_name=section_name, 394 full_name=full_name, section_name=section_name,
385 is_sorted=is_sorted) 395 is_sorted=is_sorted)
386 396
387 def Cluster(self): 397 def Cluster(self):
388 """Returns a new SymbolGroup with some symbols moved into subgroups. 398 """Returns a new SymbolGroup with some symbols moved into subgroups.
389 399
390 Subgroups include: 400 Subgroups include:
391 * Symbols that have [clone] in their name (created during inlining). 401 * Symbols that have [clone] in their name (created during inlining).
392 * Star symbols (such as "** merge strings", and "** symbol gap") 402 * Star symbols (such as "** merge strings", and "** symbol gap")
393 403
394 To view created groups: 404 To view created groups:
395 Print(clustered.Filter(lambda s: s.IsGroup()), recursive=True) 405 Print(clustered.Filter(lambda s: s.IsGroup()), recursive=True)
396 """ 406 """
397 return self._CreateTransformed(cluster_symbols.ClusterSymbols(self)) 407 return self._CreateTransformed(cluster_symbols.ClusterSymbols(self))
398 408
399 def Sorted(self, cmp_func=None, key=None, reverse=False): 409 def Sorted(self, cmp_func=None, key=None, reverse=False):
400 # Default to sorting by abs(size) then name.
401 if cmp_func is None and key is None: 410 if cmp_func is None and key is None:
402 cmp_func = lambda a, b: cmp((a.IsBss(), abs(b.size), a.name), 411 cmp_func = lambda a, b: cmp((a.IsBss(), abs(b.pss), a.name),
403 (b.IsBss(), abs(a.size), b.name)) 412 (b.IsBss(), abs(a.pss), b.name))
404 413
405 after_symbols = sorted(self._symbols, cmp_func, key, reverse) 414 after_symbols = sorted(self._symbols, cmp_func, key, reverse)
406 return self._CreateTransformed( 415 return self._CreateTransformed(
407 after_symbols, filtered_symbols=self._filtered_symbols, 416 after_symbols, filtered_symbols=self._filtered_symbols,
408 section_name=self.section_name, is_sorted=True) 417 section_name=self.section_name, is_sorted=True)
409 418
410 def SortedByName(self, reverse=False): 419 def SortedByName(self, reverse=False):
411 return self.Sorted(key=(lambda s:s.name), reverse=reverse) 420 return self.Sorted(key=(lambda s:s.name), reverse=reverse)
412 421
413 def SortedByAddress(self, reverse=False): 422 def SortedByAddress(self, reverse=False):
414 return self.Sorted(key=(lambda s:s.address), reverse=reverse) 423 return self.Sorted(key=(lambda s:(s.address, s.object_path, s.name)),
424 reverse=reverse)
415 425
416 def SortedByCount(self, reverse=False): 426 def SortedByCount(self, reverse=False):
417 return self.Sorted(key=(lambda s:len(s) if s.IsGroup() else 1), 427 return self.Sorted(key=(lambda s:len(s) if s.IsGroup() else 1),
418 reverse=not reverse) 428 reverse=not reverse)
419 429
420 def Filter(self, func): 430 def Filter(self, func):
421 filtered_and_kept = ([], []) 431 filtered_and_kept = ([], [])
422 symbol = None 432 symbol = None
423 try: 433 try:
424 for symbol in self: 434 for symbol in self:
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
537 min_count = abs(min_count) 547 min_count = abs(min_count)
538 for token, symbols in symbols_by_token.iteritems(): 548 for token, symbols in symbols_by_token.iteritems():
539 if len(symbols) >= min_count: 549 if len(symbols) >= min_count:
540 after_syms.append(self._CreateTransformed( 550 after_syms.append(self._CreateTransformed(
541 symbols, name=token, section_name=self.section_name, 551 symbols, name=token, section_name=self.section_name,
542 is_sorted=False)) 552 is_sorted=False))
543 elif include_singles: 553 elif include_singles:
544 after_syms.extend(symbols) 554 after_syms.extend(symbols)
545 else: 555 else:
546 filtered_symbols.extend(symbols) 556 filtered_symbols.extend(symbols)
547 return self._CreateTransformed( 557 grouped = self._CreateTransformed(
548 after_syms, filtered_symbols=filtered_symbols, 558 after_syms, filtered_symbols=filtered_symbols,
549 section_name=self.section_name, is_sorted=False) 559 section_name=self.section_name, is_sorted=False)
560 return grouped
550 561
551 def GroupBySectionName(self): 562 def GroupBySectionName(self):
552 return self.GroupBy(lambda s: s.section_name) 563 return self.GroupBy(lambda s: s.section_name)
553 564
554 def GroupByNamespace(self, depth=0, fallback='{global}', min_count=0): 565 def GroupByNamespace(self, depth=0, fallback='{global}', min_count=0):
555 """Groups by symbol namespace (as denoted by ::s). 566 """Groups by symbol namespace (as denoted by ::s).
556 567
557 Does not differentiate between C++ namespaces and C++ classes. 568 Does not differentiate between C++ namespaces and C++ classes.
558 569
559 Args: 570 Args:
(...skipping 14 matching lines...) Expand all
574 585
575 # Remove after the final :: (not part of the namespace). 586 # Remove after the final :: (not part of the namespace).
576 colon_idx = name.rfind('::') 587 colon_idx = name.rfind('::')
577 if colon_idx == -1: 588 if colon_idx == -1:
578 return fallback 589 return fallback
579 name = name[:colon_idx] 590 name = name[:colon_idx]
580 591
581 return _ExtractPrefixBeforeSeparator(name, '::', depth) 592 return _ExtractPrefixBeforeSeparator(name, '::', depth)
582 return self.GroupBy(extract_namespace, min_count=min_count) 593 return self.GroupBy(extract_namespace, min_count=min_count)
583 594
584 def GroupBySourcePath(self, depth=0, fallback='{no path}', 595 def GroupByPath(self, depth=0, fallback='{no path}',
585 fallback_to_object_path=True, min_count=0): 596 fallback_to_object_path=True, min_count=0):
586 """Groups by source_path. 597 """Groups by source_path.
587 598
588 Args: 599 Args:
589 depth: When 0 (default), groups by entire path. When 1, groups by 600 depth: When 0 (default), groups by entire path. When 1, groups by
590 top-level directory, when 2, groups by top 2 directories, etc. 601 top-level directory, when 2, groups by top 2 directories, etc.
591 fallback: Use this value when no namespace exists. 602 fallback: Use this value when no namespace exists.
592 fallback_to_object_path: When True (default), uses object_path when 603 fallback_to_object_path: When True (default), uses object_path when
593 source_path is missing. 604 source_path is missing.
594 min_count: Miniumum number of symbols for a group. If fewer than this many 605 min_count: Miniumum number of symbols for a group. If fewer than this many
595 symbols end up in a group, they will not be put within a group. 606 symbols end up in a group, they will not be put within a group.
596 Use a negative value to omit symbols entirely rather than 607 Use a negative value to omit symbols entirely rather than
597 include them outside of a group. 608 include them outside of a group.
598 """ 609 """
599 def extract_path(symbol): 610 def extract_path(symbol):
600 path = symbol.source_path 611 path = symbol.source_path
601 if fallback_to_object_path and not path: 612 if fallback_to_object_path and not path:
602 path = symbol.object_path 613 path = symbol.object_path
603 path = path or fallback 614 path = path or fallback
604 return _ExtractPrefixBeforeSeparator(path, os.path.sep, depth) 615 return _ExtractPrefixBeforeSeparator(path, os.path.sep, depth)
605 return self.GroupBy(extract_path, min_count=min_count) 616 return self.GroupBy(extract_path, min_count=min_count)
606 617
607 def GroupByObjectPath(self, depth=0, fallback='{no path}', min_count=0):
608 """Groups by object_path.
609
610 Args:
611 depth: When 0 (default), groups by entire path. When 1, groups by
612 top-level directory, when 2, groups by top 2 directories, etc.
613 fallback: Use this value when no namespace exists.
614 min_count: Miniumum number of symbols for a group. If fewer than this many
615 symbols end up in a group, they will not be put within a group.
616 Use a negative value to omit symbols entirely rather than
617 include them outside of a group.
618 """
619 def extract_path(symbol):
620 path = symbol.object_path or fallback
621 return _ExtractPrefixBeforeSeparator(path, os.path.sep, depth)
622 return self.GroupBy(extract_path, min_count=min_count)
623
624 618
625 class SymbolDiff(SymbolGroup): 619 class SymbolDiff(SymbolGroup):
626 """A SymbolGroup subclass representing a diff of two other SymbolGroups. 620 """A SymbolGroup subclass representing a diff of two other SymbolGroups.
627 621
628 All Symbols contained within have a |size| which is actually the size delta. 622 All Symbols contained within have a |size| which is actually the size delta.
629 Additionally, metadata is kept about which symbols were added / removed / 623 Additionally, metadata is kept about which symbols were added / removed /
630 changed. 624 changed.
631 """ 625 """
632 __slots__ = ( 626 __slots__ = (
633 '_added_ids', 627 '_added_ids',
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
722 716
723 def _ExtractPrefixBeforeSeparator(string, separator, count=1): 717 def _ExtractPrefixBeforeSeparator(string, separator, count=1):
724 idx = -len(separator) 718 idx = -len(separator)
725 prev_idx = None 719 prev_idx = None
726 for _ in xrange(count): 720 for _ in xrange(count):
727 idx = string.find(separator, idx + len(separator)) 721 idx = string.find(separator, idx + len(separator))
728 if idx < 0: 722 if idx < 0:
729 break 723 break
730 prev_idx = idx 724 prev_idx = idx
731 return string[:prev_idx] 725 return string[:prev_idx]
OLDNEW
« no previous file with comments | « tools/binary_size/libsupersize/main.py ('k') | tools/binary_size/libsupersize/testdata/Archive.golden » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698