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

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

Issue 2936033002: Supersize diff rewrite + tweaks (Closed)
Patch Set: review comnts Created 3 years, 6 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 """Logic for diffing two SizeInfo objects.""" 4 """Logic for diffing two SizeInfo objects."""
5 5
6 import collections 6 import collections
7 import re 7 import re
8 8
9 import models 9 import models
10 10
(...skipping 24 matching lines...) Expand all
35 # Use section rather than section_name since clang & gcc use 35 # Use section rather than section_name since clang & gcc use
36 # .data.rel.ro vs .data.rel.ro.local. 36 # .data.rel.ro vs .data.rel.ro.local.
37 if '.' not in name: 37 if '.' not in name:
38 return (symbol.section, name) 38 return (symbol.section, name)
39 39
40 # Compiler or Linker generated symbol. 40 # Compiler or Linker generated symbol.
41 name = re.sub(r'[.0-9]', '', name) # Strip out all numbers and dots. 41 name = re.sub(r'[.0-9]', '', name) # Strip out all numbers and dots.
42 return (symbol.section, name, symbol.object_path) 42 return (symbol.section, name, symbol.object_path)
43 43
44 44
45 def _CloneSymbol(sym, size):
46 """Returns a copy of |sym| with an updated |size|.
47
48 Padding and aliases are not copied.
49 """
50 return models.Symbol(
51 sym.section_name, size, address=sym.address, full_name=sym.full_name,
52 template_name=sym.template_name, name=sym.name,
53 source_path=sym.source_path, object_path=sym.object_path, flags=sym.flags)
54
55
56 def _CloneAlias(sym, diffed_alias):
57 """Returns a copy of |sym| and making it an alias of |diffed_alias|."""
58 ret = _CloneSymbol(sym, diffed_alias.size_without_padding)
59 ret.padding = diffed_alias.padding
60 ret.aliases = diffed_alias.aliases
61 ret.aliases.append(ret)
62 return ret
63
64
65 def _DiffSymbol(before_sym, after_sym, diffed_symbol_by_after_aliases,
66 padding_by_section_name):
67 diffed_alias = None
68 if after_sym.aliases:
69 diffed_alias = diffed_symbol_by_after_aliases.get(id(after_sym.aliases))
70
71 if diffed_alias:
72 ret = _CloneAlias(after_sym, diffed_alias)
73 else:
74 size_diff = (after_sym.size_without_padding -
75 before_sym.size_without_padding)
76 ret = _CloneSymbol(after_sym, size_diff)
77 # Diffs are more stable when comparing size without padding, except when
78 # the symbol is a padding-only symbol.
79 if after_sym.size_without_padding == 0 and size_diff == 0:
80 ret.padding = after_sym.padding - before_sym.padding
81 else:
82 padding_diff = after_sym.padding - before_sym.padding
83 padding_by_section_name[ret.section_name] += padding_diff
84
85 # If this is the first matched symbol of an alias group, initialize its
86 # aliases list. The remaining aliases will be appended when diff'ed.
87 if after_sym.aliases:
88 ret.aliases = [ret]
89 diffed_symbol_by_after_aliases[id(after_sym.aliases)] = ret
90 return ret
91
92
93 def _CloneUnmatched(after_symbols, diffed_symbol_by_after_aliases):
94 ret = [None] * len(after_symbols)
95 for i, sym in enumerate(after_symbols):
96 cloned = sym
97 if sym.aliases:
98 diffed_alias = diffed_symbol_by_after_aliases.get(id(sym.aliases))
99 if diffed_alias:
100 # At least one alias was diffed.
101 cloned = _CloneAlias(sym, diffed_alias)
102 ret[i] = cloned
103 return ret
104
105
106 def _NegateAndClone(before_symbols, matched_before_aliases,
107 negated_symbol_by_before_aliases):
108 ret = [None] * len(before_symbols)
109 for i, sym in enumerate(before_symbols):
110 if sym.aliases:
111 negated_alias = negated_symbol_by_before_aliases.get(id(sym.aliases))
112 if negated_alias:
113 cloned = _CloneAlias(sym, negated_alias)
114 else:
115 all_aliases_removed = id(sym.aliases) not in matched_before_aliases
116 # If all alises are removed, then given them negative size to reflect
117 # the savings.
118 if all_aliases_removed:
119 cloned = _CloneSymbol(sym, -sym.size_without_padding)
120 cloned.padding = -sym.padding
121 else:
122 # But if only a subset of aliases are removed, do not actually treat
123 # them as aliases anymore, or else they will weigh down the PSS of
124 # the symbols that were not removed.
125 cloned = _CloneSymbol(sym, 0)
126 cloned.aliases = [cloned]
127 negated_symbol_by_before_aliases[id(sym.aliases)] = cloned
128 else:
129 cloned = _CloneSymbol(sym, -sym.size_without_padding)
130 cloned.padding = -sym.padding
131 ret[i] = cloned
132 return ret
133
134
135 def _DiffSymbolGroups(before, after): 45 def _DiffSymbolGroups(before, after):
136 before_symbols_by_key = collections.defaultdict(list) 46 before_symbols_by_key = collections.defaultdict(list)
137 for s in before: 47 for s in before:
138 before_symbols_by_key[_SymbolKey(s)].append(s) 48 before_symbols_by_key[_SymbolKey(s)].append(s)
139 49
140 similar = [] 50 delta_symbols = []
141 diffed_symbol_by_after_aliases = {} 51 # For changed symbols, padding is zeroed out. In order to not lose the
142 matched_before_aliases = set()
143 unmatched_after_syms = []
144 # For similar symbols, padding is zeroed out. In order to not lose the
145 # information entirely, store it in aggregate. 52 # information entirely, store it in aggregate.
146 padding_by_section_name = collections.defaultdict(int) 53 padding_by_section_name = collections.defaultdict(int)
147 54
148 # Step 1: Create all delta symbols and record unmatched symbols. 55 # Create a DeltaSymbol for each after symbol.
149 for after_sym in after: 56 for after_sym in after:
150 matching_syms = before_symbols_by_key.get(_SymbolKey(after_sym)) 57 matching_syms = before_symbols_by_key.get(_SymbolKey(after_sym))
58 before_sym = None
151 if matching_syms: 59 if matching_syms:
152 before_sym = matching_syms.pop(0) 60 before_sym = matching_syms.pop(0)
153 if before_sym.IsGroup() and after_sym.IsGroup(): 61 # Padding tracked in aggregate, except for padding-only symbols.
154 similar.append(_DiffSymbolGroups(before_sym, after_sym)) 62 if before_sym.size_without_padding:
155 else: 63 padding_by_section_name[before_sym.section_name] += (
156 if before_sym.aliases: 64 after_sym.padding_pss - before_sym.padding_pss)
157 matched_before_aliases.add(id(before_sym.aliases)) 65 delta_symbols.append(models.DeltaSymbol(before_sym, after_sym))
158 similar.append(
159 _DiffSymbol(before_sym, after_sym, diffed_symbol_by_after_aliases,
160 padding_by_section_name))
161 else:
162 unmatched_after_syms.append(after_sym)
163 continue
164 66
165 # Step 2: Copy symbols only in "after" (being careful with aliases). 67 # Create a DeltaSymbol for each unmatched before symbol.
166 added = _CloneUnmatched(unmatched_after_syms, diffed_symbol_by_after_aliases) 68 for remaining_syms in before_symbols_by_key.itervalues():
69 for before_sym in remaining_syms:
70 delta_symbols.append(models.DeltaSymbol(before_sym, None))
167 71
168 # Step 3: Negate symbols only in "before" (being careful with aliases). 72 # Create a DeltaSymbol to represent the zero'd out padding of matched symbols.
169 removed = []
170 negated_symbol_by_before_aliases = {}
171 for remaining_syms in before_symbols_by_key.itervalues():
172 removed.extend(_NegateAndClone(remaining_syms, matched_before_aliases,
173 negated_symbol_by_before_aliases))
174
175 # Step 4: Create ** symbols to represent padding differences.
176 for section_name, padding in padding_by_section_name.iteritems(): 73 for section_name, padding in padding_by_section_name.iteritems():
177 if padding != 0: 74 if padding != 0:
178 similar.append(models.Symbol( 75 after_sym = models.Symbol(section_name, padding,
179 section_name, padding, 76 name="** aggregate padding of diff'ed symbols")
180 name="** aggregate padding of diff'ed symbols")) 77 after_sym.padding = padding
181 return models.SymbolDiff(added, removed, similar) 78 delta_symbols.append(models.DeltaSymbol(None, after_sym))
79
80 return models.DeltaSymbolGroup(delta_symbols)
182 81
183 82
184 def Diff(before, after): 83 def Diff(before, after):
185 """Diffs two SizeInfo objects. Returns a SizeInfoDiff.""" 84 """Diffs two SizeInfo objects. Returns a DeltaSizeInfo."""
186 assert isinstance(before, models.SizeInfo) 85 assert isinstance(before, models.SizeInfo)
187 assert isinstance(after, models.SizeInfo) 86 assert isinstance(after, models.SizeInfo)
188 section_sizes = {k: after.section_sizes.get(k, 0) - v 87 section_sizes = {k: after.section_sizes.get(k, 0) - v
189 for k, v in before.section_sizes.iteritems()} 88 for k, v in before.section_sizes.iteritems()}
190 for k, v in after.section_sizes.iteritems(): 89 for k, v in after.section_sizes.iteritems():
191 if k not in section_sizes: 90 if k not in section_sizes:
192 section_sizes[k] = v 91 section_sizes[k] = v
193 92
194 symbol_diff = _DiffSymbolGroups(before.raw_symbols, after.raw_symbols) 93 symbol_diff = _DiffSymbolGroups(before.raw_symbols, after.raw_symbols)
195 return models.SizeInfoDiff(section_sizes, symbol_diff, before.metadata, 94 return models.DeltaSizeInfo(section_sizes, symbol_diff, before.metadata,
196 after.metadata) 95 after.metadata)
OLDNEW
« no previous file with comments | « tools/binary_size/libsupersize/describe.py ('k') | tools/binary_size/libsupersize/file_format.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698