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

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

Issue 2884283002: supersize: Fix diff logic for changed vs unchanged of groups (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 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
52 't': '.text', 52 't': '.text',
53 } 53 }
54 54
55 FLAG_ANONYMOUS = 1 55 FLAG_ANONYMOUS = 1
56 FLAG_STARTUP = 2 56 FLAG_STARTUP = 2
57 FLAG_UNLIKELY = 4 57 FLAG_UNLIKELY = 4
58 FLAG_REL = 8 58 FLAG_REL = 8
59 FLAG_REL_LOCAL = 16 59 FLAG_REL_LOCAL = 16
60 FLAG_GENERATED_SOURCE = 32 60 FLAG_GENERATED_SOURCE = 32
61 61
62 DIFF_STATUS_UNCHANGED = 0
63 DIFF_STATUS_CHANGED = 1
64 DIFF_STATUS_ADDED = 2
65 DIFF_STATUS_REMOVED = 3
66
62 67
63 class SizeInfo(object): 68 class SizeInfo(object):
64 """Represents all size information for a single binary. 69 """Represents all size information for a single binary.
65 70
66 Fields: 71 Fields:
67 section_sizes: A dict of section_name -> size. 72 section_sizes: A dict of section_name -> size.
68 raw_symbols: A list of all symbols, sorted by address. 73 raw_symbols: A list of all symbols, sorted by address.
69 symbols: A SymbolGroup containing all symbols. By default, these are the 74 symbols: A SymbolGroup containing all symbols. By default, these are the
70 same as raw_symbols, but may contain custom groupings when it is 75 same as raw_symbols, but may contain custom groupings when it is
71 desirable to convey the result of a query along with section_sizes and 76 desirable to convey the result of a query along with section_sizes and
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after
292 return 'Group(full_name=%s,count=%d,size=%d)' % ( 297 return 'Group(full_name=%s,count=%d,size=%d)' % (
293 self.full_name, len(self), self.size) 298 self.full_name, len(self), self.size)
294 299
295 def __iter__(self): 300 def __iter__(self):
296 return iter(self._symbols) 301 return iter(self._symbols)
297 302
298 def __len__(self): 303 def __len__(self):
299 return len(self._symbols) 304 return len(self._symbols)
300 305
301 def __eq__(self, other): 306 def __eq__(self, other):
302 return self._symbols == other._symbols 307 return isinstance(other, SymbolGroup) and self._symbols == other._symbols
303 308
304 def __getitem__(self, key): 309 def __getitem__(self, key):
305 """|key| can be an index or an address. 310 """|key| can be an index or an address.
306 311
307 Raises if multiple symbols map to the address. 312 Raises if multiple symbols map to the address.
308 """ 313 """
309 if isinstance(key, slice): 314 if isinstance(key, slice):
310 return self._symbols.__getitem__(key) 315 return self._symbols.__getitem__(key)
311 if isinstance(key, basestring) or key > len(self._symbols): 316 if isinstance(key, basestring) or key > len(self._symbols):
312 found = self.WhereAddressInRange(key) 317 found = self.WhereAddressInRange(key)
(...skipping 329 matching lines...) Expand 10 before | Expand all | Expand 10 after
642 class SymbolDiff(SymbolGroup): 647 class SymbolDiff(SymbolGroup):
643 """A SymbolGroup subclass representing a diff of two other SymbolGroups. 648 """A SymbolGroup subclass representing a diff of two other SymbolGroups.
644 649
645 All Symbols contained within have a |size| which is actually the size delta. 650 All Symbols contained within have a |size| which is actually the size delta.
646 Additionally, metadata is kept about which symbols were added / removed / 651 Additionally, metadata is kept about which symbols were added / removed /
647 changed. 652 changed.
648 """ 653 """
649 __slots__ = ( 654 __slots__ = (
650 '_added_ids', 655 '_added_ids',
651 '_removed_ids', 656 '_removed_ids',
657 '_diff_status',
658 '_changed_count',
652 ) 659 )
653 660
654 def __init__(self, added, removed, similar): 661 def __init__(self, added, removed, similar):
655 self._added_ids = set(id(s) for s in added) 662 self._added_ids = set(id(s) for s in added)
656 self._removed_ids = set(id(s) for s in removed) 663 self._removed_ids = set(id(s) for s in removed)
664 self._diff_status = DIFF_STATUS_CHANGED
665 self._changed_count = None
657 symbols = [] 666 symbols = []
658 symbols.extend(added) 667 symbols.extend(added)
659 symbols.extend(removed) 668 symbols.extend(removed)
660 symbols.extend(similar) 669 symbols.extend(similar)
661 super(SymbolDiff, self).__init__(symbols) 670 super(SymbolDiff, self).__init__(symbols)
662 671
663 def __repr__(self): 672 def __repr__(self):
664 return '%s(%d added, %d removed, %d changed, %d unchanged, size=%d)' % ( 673 return '%s(%d added, %d removed, %d changed, %d unchanged, size=%d)' % (
665 'SymbolGroup', self.added_count, self.removed_count, self.changed_count, 674 'SymbolGroup', self.added_count, self.removed_count, self.changed_count,
666 self.unchanged_count, self.size) 675 self.unchanged_count, self.size)
667 676
668 def _CreateTransformed(self, symbols, filtered_symbols=None, full_name=None, 677 def _CreateTransformed(self, symbols, filtered_symbols=None, full_name=None,
669 template_name=None, name=None, section_name=None, 678 template_name=None, name=None, section_name=None,
670 is_sorted=None): 679 is_sorted=None):
671 # Printing sorts, so short-circuit the same symbols case. 680 new_added_ids = set()
672 if len(symbols) == len(self._symbols): 681 new_removed_ids = set()
673 new_added_ids = self._added_ids 682 group_diff_status = DIFF_STATUS_UNCHANGED
674 new_removed_ids = self._removed_ids 683 changed_count = 0
675 else: 684 if symbols:
676 old_added_ids = self._added_ids 685 group_diff_status = self.DiffStatus(symbols[0])
677 old_removed_ids = self._removed_ids
678
679 def get_status(sym):
680 obj_id = id(sym)
681 if obj_id in old_added_ids:
682 return 0
683 if obj_id in old_removed_ids:
684 return 1
685 if sym.IsGroup():
686 first_status = get_status(sym[0])
687 if all(get_status(s) == first_status for s in sym[1:]):
688 return first_status
689 return 2
690
691 new_added_ids = set()
692 new_removed_ids = set()
693 for sym in symbols: 686 for sym in symbols:
694 status = get_status(sym) 687 status = self.DiffStatus(sym)
695 if status == 0: 688 if status != group_diff_status:
689 group_diff_status = DIFF_STATUS_CHANGED
690 if status == DIFF_STATUS_ADDED:
696 new_added_ids.add(id(sym)) 691 new_added_ids.add(id(sym))
697 elif status == 1: 692 elif status == DIFF_STATUS_REMOVED:
698 new_removed_ids.add(id(sym)) 693 new_removed_ids.add(id(sym))
694 elif status == DIFF_STATUS_CHANGED:
695 changed_count += 1
699 696
700 ret = SymbolDiff.__new__(SymbolDiff) 697 ret = SymbolDiff.__new__(SymbolDiff)
701 ret._added_ids = new_added_ids 698 ret._added_ids = new_added_ids
702 ret._removed_ids = new_removed_ids 699 ret._removed_ids = new_removed_ids
700 ret._diff_status = group_diff_status
701 ret._changed_count = changed_count
703 super(SymbolDiff, ret).__init__( 702 super(SymbolDiff, ret).__init__(
704 symbols, filtered_symbols=filtered_symbols, full_name=full_name, 703 symbols, filtered_symbols=filtered_symbols, full_name=full_name,
705 template_name=template_name, name=name, section_name=section_name, 704 template_name=template_name, name=name, section_name=section_name,
706 is_sorted=is_sorted) 705 is_sorted=is_sorted)
707 return ret 706 return ret
708 707
709 @property 708 @property
710 def added_count(self): 709 def added_count(self):
711 return len(self._added_ids) 710 return len(self._added_ids)
712 711
713 @property 712 @property
714 def removed_count(self): 713 def removed_count(self):
715 return len(self._removed_ids) 714 return len(self._removed_ids)
716 715
717 @property 716 @property
718 def changed_count(self): 717 def changed_count(self):
719 not_changed = self.unchanged_count + self.added_count + self.removed_count 718 if self._changed_count is None:
720 return len(self) - not_changed 719 self._changed_count = sum(1 for s in self if self.IsChanged(s))
720 return self._changed_count
721 721
722 @property 722 @property
723 def unchanged_count(self): 723 def unchanged_count(self):
724 return sum(1 for s in self if self.IsSimilar(s) and s.size == 0) 724 return (len(self) - self.changed_count - self.added_count -
725 self.removed_count)
726
727 def DiffStatus(self, sym):
728 # Groups store their own status, computed during _CreateTransformed().
729 if sym.IsGroup():
730 return sym._diff_status
731 sym_id = id(sym)
732 if sym_id in self._added_ids:
733 return DIFF_STATUS_ADDED
734 if sym_id in self._removed_ids:
735 return DIFF_STATUS_REMOVED
736 # 0 --> unchanged
737 # 1 --> changed
738 return int(sym.size != 0)
739
740 def IsUnchanged(self, sym):
741 return self.DiffStatus(sym) == DIFF_STATUS_UNCHANGED
742
743 def IsChanged(self, sym):
744 return self.DiffStatus(sym) == DIFF_STATUS_CHANGED
725 745
726 def IsAdded(self, sym): 746 def IsAdded(self, sym):
727 return id(sym) in self._added_ids 747 return self.DiffStatus(sym) == DIFF_STATUS_ADDED
728
729 def IsSimilar(self, sym):
730 key = id(sym)
731 return key not in self._added_ids and key not in self._removed_ids
732 748
733 def IsRemoved(self, sym): 749 def IsRemoved(self, sym):
734 return id(sym) in self._removed_ids 750 return self.DiffStatus(sym) == DIFF_STATUS_REMOVED
735 751
736 def WhereNotUnchanged(self): 752 def WhereNotUnchanged(self):
737 return self.Filter(lambda s: not self.IsSimilar(s) or s.size) 753 return self.Filter(lambda s: not self.IsUnchanged(s))
738 754
739 755
740 def _ExtractPrefixBeforeSeparator(string, separator, count): 756 def _ExtractPrefixBeforeSeparator(string, separator, count):
741 idx = -len(separator) 757 idx = -len(separator)
742 prev_idx = None 758 prev_idx = None
743 for _ in xrange(count): 759 for _ in xrange(count):
744 idx = string.find(separator, idx + len(separator)) 760 idx = string.find(separator, idx + len(separator))
745 if idx < 0: 761 if idx < 0:
746 break 762 break
747 prev_idx = idx 763 prev_idx = idx
748 return string[:prev_idx] 764 return string[:prev_idx]
749 765
750 766
751 def _ExtractSuffixAfterSeparator(string, separator, count): 767 def _ExtractSuffixAfterSeparator(string, separator, count):
752 prev_idx = len(string) + 1 768 prev_idx = len(string) + 1
753 for _ in xrange(count): 769 for _ in xrange(count):
754 idx = string.rfind(separator, 0, prev_idx - 1) 770 idx = string.rfind(separator, 0, prev_idx - 1)
755 if idx < 0: 771 if idx < 0:
756 break 772 break
757 prev_idx = idx 773 prev_idx = idx
758 return string[:prev_idx] 774 return string[:prev_idx]
OLDNEW
« no previous file with comments | « tools/binary_size/libsupersize/integration_test.py ('k') | tools/binary_size/libsupersize/testdata/Console.golden » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698