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

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

Issue 2854173003: supersize: Don't cluster by default. Make Diff() accept only SizeInfo. (Closed)
Patch Set: 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 11 matching lines...) Expand all
22 are removed from both full_name and name during normalization). 22 are removed from both full_name and name during normalization).
23 * section_name: E.g. ".text", ".rodata", ".data.rel.local" 23 * section_name: E.g. ".text", ".rodata", ".data.rel.local"
24 * 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".
25 """ 25 """
26 26
27 import collections 27 import collections
28 import logging 28 import logging
29 import os 29 import os
30 import re 30 import re
31 31
32 import cluster_symbols
32 import match_util 33 import match_util
33 34
34 35
35 METADATA_GIT_REVISION = 'git_revision' 36 METADATA_GIT_REVISION = 'git_revision'
36 METADATA_APK_FILENAME = 'apk_file_name' # Path relative to output_directory. 37 METADATA_APK_FILENAME = 'apk_file_name' # Path relative to output_directory.
37 METADATA_MAP_FILENAME = 'map_file_name' # Path relative to output_directory. 38 METADATA_MAP_FILENAME = 'map_file_name' # Path relative to output_directory.
38 METADATA_ELF_ARCHITECTURE = 'elf_arch' # "Machine" field from readelf -h 39 METADATA_ELF_ARCHITECTURE = 'elf_arch' # "Machine" field from readelf -h
39 METADATA_ELF_FILENAME = 'elf_file_name' # Path relative to output_directory. 40 METADATA_ELF_FILENAME = 'elf_file_name' # Path relative to output_directory.
40 METADATA_ELF_MTIME = 'elf_mtime' # int timestamp in utc. 41 METADATA_ELF_MTIME = 'elf_mtime' # int timestamp in utc.
41 METADATA_ELF_BUILD_ID = 'elf_build_id' 42 METADATA_ELF_BUILD_ID = 'elf_build_id'
(...skipping 19 matching lines...) Expand all
61 if clone_idx != -1: 62 if clone_idx != -1:
62 return name[:clone_idx] 63 return name[:clone_idx]
63 return name 64 return name
64 65
65 66
66 class SizeInfo(object): 67 class SizeInfo(object):
67 """Represents all size information for a single binary. 68 """Represents all size information for a single binary.
68 69
69 Fields: 70 Fields:
70 section_sizes: A dict of section_name -> size. 71 section_sizes: A dict of section_name -> size.
71 raw_symbols: A flat list of all symbols. 72 symbols: A SymbolGroup containing all symbols, sorted by address.
72 symbols: A SymbolGroup containing raw_symbols, but with some Symbols grouped
73 into sub-SymbolGroups.
74 metadata: A dict. 73 metadata: A dict.
75 """ 74 """
76 __slots__ = ( 75 __slots__ = (
77 'section_sizes', 76 'section_sizes',
78 'raw_symbols',
79 'symbols', 77 'symbols',
80 'metadata', 78 'metadata',
81 ) 79 )
82 80
83 """Root size information.""" 81 """Root size information."""
84 def __init__(self, section_sizes, raw_symbols, grouped_symbols=None, 82 def __init__(self, section_sizes, symbols, metadata=None):
85 metadata=None):
86 self.section_sizes = section_sizes # E.g. {'.text': 0} 83 self.section_sizes = section_sizes # E.g. {'.text': 0}
87 # List of symbols sorted by address per-section. 84 self.symbols = symbols
88 self.raw_symbols = raw_symbols
89 # Root SymbolGroup. Cloned symbols grouped together within sub-SymbolGroups.
90 self.symbols = grouped_symbols
91 self.metadata = metadata or {} 85 self.metadata = metadata or {}
92 86
87 def Cluster(self):
88 """Returns a new SizeInfo with some symbols moved into subgroups.
89
90 See SymbolGroup.Cluster() for more details.
91 """
92 return SizeInfo(self.section_sizes, self.symbols.Cluster(), self.metadata)
93
93 94
94 class SizeInfoDiff(object): 95 class SizeInfoDiff(object):
95 """What you get when you Diff() two SizeInfo objects. 96 """What you get when you Diff() two SizeInfo objects.
96 97
97 Fields: 98 Fields:
98 section_sizes: A dict of section_name -> size delta. 99 section_sizes: A dict of section_name -> size delta.
99 symbols: A SymbolDiff with all symbols in it. 100 symbols: A SymbolDiff with all symbols in it.
100 before_metadata: metadata of the "before" SizeInfo. 101 before_metadata: metadata of the "before" SizeInfo.
101 after_metadata: metadata of the "after" SizeInfo. 102 after_metadata: metadata of the "after" SizeInfo.
102 """ 103 """
(...skipping 268 matching lines...) Expand 10 before | Expand all | Expand 10 after
371 return self._padding 372 return self._padding
372 373
373 @property 374 @property
374 def aliases(self): 375 def aliases(self):
375 return None 376 return None
376 377
377 def IsGroup(self): 378 def IsGroup(self):
378 return True 379 return True
379 380
380 def _CreateTransformed(self, symbols, filtered_symbols=None, name=None, 381 def _CreateTransformed(self, symbols, filtered_symbols=None, name=None,
381 section_name=None, is_sorted=None): 382 full_name=None, section_name=None, is_sorted=None):
382 if is_sorted is None: 383 if is_sorted is None:
383 is_sorted = self.is_sorted 384 is_sorted = self.is_sorted
384 return SymbolGroup(symbols, filtered_symbols=filtered_symbols, name=name, 385 return SymbolGroup(symbols, filtered_symbols=filtered_symbols, name=name,
385 section_name=section_name, is_sorted=is_sorted) 386 full_name=full_name, section_name=section_name,
387 is_sorted=is_sorted)
388
389 def Cluster(self):
390 """Returns a new SymbolGroup with some symbols moved into subgroups.
391
392 Subgroups include:
393 * Symbols that have [clone] in their name (created during inlining).
394 * Star symbols (such as "** merge strings", and "** symbol gap")
395
396 To view created groups:
397 Print(clustered.Filter(lambda s: s.IsGroup()), recursive=True)
398 """
399 return self._CreateTransformed(cluster_symbols.ClusterSymbols(self))
386 400
387 def Sorted(self, cmp_func=None, key=None, reverse=False): 401 def Sorted(self, cmp_func=None, key=None, reverse=False):
388 # Default to sorting by abs(size) then name. 402 # Default to sorting by abs(size) then name.
389 if cmp_func is None and key is None: 403 if cmp_func is None and key is None:
390 cmp_func = lambda a, b: cmp((a.IsBss(), abs(b.size), a.name), 404 cmp_func = lambda a, b: cmp((a.IsBss(), abs(b.size), a.name),
391 (b.IsBss(), abs(a.size), b.name)) 405 (b.IsBss(), abs(a.size), b.name))
392 406
393 after_symbols = sorted(self._symbols, cmp_func, key, reverse) 407 after_symbols = sorted(self._symbols, cmp_func, key, reverse)
394 return self._CreateTransformed( 408 return self._CreateTransformed(
395 after_symbols, filtered_symbols=self._filtered_symbols, 409 after_symbols, filtered_symbols=self._filtered_symbols,
(...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after
620 symbols.extend(similar) 634 symbols.extend(similar)
621 super(SymbolDiff, self).__init__(symbols, name=name, full_name=full_name, 635 super(SymbolDiff, self).__init__(symbols, name=name, full_name=full_name,
622 section_name=section_name) 636 section_name=section_name)
623 637
624 def __repr__(self): 638 def __repr__(self):
625 return '%s(%d added, %d removed, %d changed, %d unchanged, size=%d)' % ( 639 return '%s(%d added, %d removed, %d changed, %d unchanged, size=%d)' % (
626 'SymbolGroup', self.added_count, self.removed_count, self.changed_count, 640 'SymbolGroup', self.added_count, self.removed_count, self.changed_count,
627 self.unchanged_count, self.size) 641 self.unchanged_count, self.size)
628 642
629 def _CreateTransformed(self, symbols, filtered_symbols=None, name=None, 643 def _CreateTransformed(self, symbols, filtered_symbols=None, name=None,
630 section_name=None, is_sorted=None): 644 full_name=None, section_name=None, is_sorted=None):
645 # Printing sorts, so short-circuit the same symbols case.
646 if len(symbols) == len(self._symbols):
647 new_added_ids = self._added_ids
648 new_removed_ids = self._removed_ids
649 else:
650 old_added_ids = self._added_ids
651 old_removed_ids = self._removed_ids
652
653 def get_status(sym):
654 obj_id = id(sym)
655 if obj_id in old_added_ids:
656 return 0
657 if obj_id in old_removed_ids:
658 return 1
659 if sym.IsGroup():
660 first_status = get_status(sym[0])
661 if all(get_status(s) == first_status for s in sym[1:]):
662 return first_status
663 return 2
664
665 new_added_ids = set()
666 new_removed_ids = set()
667 for sym in symbols:
668 status = get_status(sym)
669 if status == 0:
670 new_added_ids.add(id(sym))
671 elif status == 1:
672 new_removed_ids.add(id(sym))
673
631 ret = SymbolDiff.__new__(SymbolDiff) 674 ret = SymbolDiff.__new__(SymbolDiff)
632 # Printing sorts, so fast-path the same symbols case. 675 ret._added_ids = new_added_ids
633 if len(symbols) == len(self._symbols): 676 ret._removed_ids = new_removed_ids
634 ret._added_ids = self._added_ids
635 ret._removed_ids = self._removed_ids
636 else:
637 ret._added_ids = set(id(s) for s in symbols if self.IsAdded(s))
638 ret._removed_ids = set(id(s) for s in symbols if self.IsRemoved(s))
639 super(SymbolDiff, ret).__init__( 677 super(SymbolDiff, ret).__init__(
640 symbols, filtered_symbols=filtered_symbols, name=name, 678 symbols, filtered_symbols=filtered_symbols, name=name,
641 section_name=section_name, is_sorted=is_sorted) 679 full_name=full_name, section_name=section_name, is_sorted=is_sorted)
642 return ret 680 return ret
643 681
644 @property 682 @property
645 def added_count(self): 683 def added_count(self):
646 return len(self._added_ids) 684 return len(self._added_ids)
647 685
648 @property 686 @property
649 def removed_count(self): 687 def removed_count(self):
650 return len(self._removed_ids) 688 return len(self._removed_ids)
651 689
(...skipping 22 matching lines...) Expand all
674 712
675 def _ExtractPrefixBeforeSeparator(string, separator, count=1): 713 def _ExtractPrefixBeforeSeparator(string, separator, count=1):
676 idx = -len(separator) 714 idx = -len(separator)
677 prev_idx = None 715 prev_idx = None
678 for _ in xrange(count): 716 for _ in xrange(count):
679 idx = string.find(separator, idx + len(separator)) 717 idx = string.find(separator, idx + len(separator))
680 if idx < 0: 718 if idx < 0:
681 break 719 break
682 prev_idx = idx 720 prev_idx = idx
683 return string[:prev_idx] 721 return string[:prev_idx]
OLDNEW
« no previous file with comments | « tools/binary_size/libsupersize/integration_test.py ('k') | tools/binary_size/libsupersize/testdata/Archive.golden » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698