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

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

Issue 2832253004: supersize: nm in progress (Closed)
Patch Set: supersize: Track symbol aliases and shared symbols 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
(Empty)
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
3 # found in the LICENSE file.
4 """Logic for diffing two SizeInfo objects."""
5
6 import collections
7
8 import models
9
10
11 def _CloneSymbol(sym, size):
12 """Returns a copy of |sym| with an updated |size|.
13
14 Padding and aliases are not copied.
15 """
16 return models.Symbol(
17 sym.section_name, size, address=sym.address, name=sym.name,
18 source_path=sym.source_path, object_path=sym.object_path,
19 full_name=sym.full_name, flags=sym.flags)
20
21
22 def _CloneAlias(sym, diffed_alias):
23 """Returns a copy of |sym| and making it an alias of |diffed_alias|."""
24 ret = _CloneSymbol(sym, diffed_alias.size_without_padding)
25 ret.padding = diffed_alias.padding
26 ret.aliases = diffed_alias.aliases
27 ret.aliases.append(ret)
28 return ret
29
30
31 def _DiffSymbol(before_sym, after_sym, diffed_symbol_by_after_aliases,
32 padding_by_section_name):
33 diffed_alias = None
34 if after_sym.aliases:
35 diffed_alias = diffed_symbol_by_after_aliases.get(id(after_sym.aliases))
36
37 if diffed_alias:
38 ret = _CloneAlias(after_sym, diffed_alias)
39 else:
40 size_diff = (after_sym.size_without_padding -
41 before_sym.size_without_padding)
42 ret = _CloneSymbol(after_sym, size_diff)
43 # Diffs are more stable when comparing size without padding, except when
44 # the symbol is a padding-only symbol.
45 if after_sym.size_without_padding == 0 and size_diff == 0:
46 ret.padding = after_sym.padding - before_sym.padding
47 else:
48 padding_diff = after_sym.padding - before_sym.padding
49 padding_by_section_name[ret.section_name] += padding_diff
50
51 if after_sym.aliases:
52 ret.aliases = [ret]
53 diffed_symbol_by_after_aliases[id(after_sym.aliases)] = ret
54 return ret
55
56
57 def _CloneUnmatched(after_symbols, diffed_symbol_by_after_aliases):
58 ret = []
59 for sym in after_symbols:
60 cloned = sym
61 if sym.IsGroup():
62 cloned = models.SymbolDiff(
63 [], _CloneUnmatched(sym, diffed_symbol_by_after_aliases), [],
64 name=sym.name, full_name=sym.full_name, section_name=sym.section_name)
65 elif sym.aliases:
66 diffed_alias = diffed_symbol_by_after_aliases.get(id(sym.aliases))
67 if diffed_alias:
68 # At least one alias was diffed.
69 cloned = _CloneAlias(sym, diffed_alias)
70 ret.append(cloned)
71 return ret
72
73
74 def _NegateAndClone(before_symbols, matched_before_aliases,
75 negated_symbol_by_before_aliases):
76 ret = []
77 for sym in before_symbols:
78 if sym.IsGroup():
79 cloned = models.SymbolDiff(
80 [], _NegateAndClone(sym, matched_before_aliases,
81 negated_symbol_by_before_aliases), [],
82 name=sym.name, full_name=sym.full_name, section_name=sym.section_name)
83 else:
84 negated_alias = None
85 if sym.aliases:
86 negated_alias = negated_symbol_by_before_aliases.get(id(sym.aliases))
87 if negated_alias:
88 cloned = _CloneAlias(sym, negated_alias)
89 else:
90 all_aliases_removed = id(sym.aliases) not in matched_before_aliases
91 if all_aliases_removed:
92 cloned = _CloneSymbol(sym, -sym.size_without_padding)
93 cloned.padding = -sym.padding
94 else:
95 cloned = _CloneSymbol(sym, 0)
96 cloned.aliases = [cloned]
97 negated_symbol_by_before_aliases[id(sym.aliases)] = cloned
98 else:
99 cloned = _CloneSymbol(sym, -sym.size_without_padding)
100 cloned.padding = -sym.padding
101 ret.append(cloned)
102 return ret
103
104
105 # TODO(agrieve): I doubt this works correctly for aliases that include [clone]
106 # symbols that have been grouped into nested SymbolGroups. I'm guessing this
107 # won't be a big issue if it's not correct though (likely won't come up, and
108 # if it does will account for small size).
109 def _DiffSymbolGroups(before, after):
110 before_symbols_by_key = collections.defaultdict(list)
111 for s in before:
112 before_symbols_by_key[s._Key()].append(s)
113
114 similar = []
115 diffed_symbol_by_after_aliases = {}
116 matched_before_aliases = set()
117 unmatched_after_syms = []
118 # For similar symbols, padding is zeroed out. In order to not lose the
119 # information entirely, store it in aggregate.
120 padding_by_section_name = collections.defaultdict(int)
121
122 # Step 1: Create all delta symbols and record unmatched symbols.
123 for after_sym in after:
124 matching_syms = before_symbols_by_key.get(after_sym._Key())
125 if matching_syms:
126 before_sym = matching_syms.pop(0)
127 if before_sym.IsGroup() and after_sym.IsGroup():
128 similar.append(_DiffSymbolGroups(before_sym, after_sym))
129 else:
130 if before_sym.aliases:
131 matched_before_aliases.add(id(before_sym.aliases))
132 similar.append(
133 _DiffSymbol(before_sym, after_sym, diffed_symbol_by_after_aliases,
134 padding_by_section_name))
135 else:
136 unmatched_after_syms.append(after_sym)
137 continue
138
139 # Step 2: Copy symbols only in "after" (being careful with aliases).
140 added = _CloneUnmatched(unmatched_after_syms, diffed_symbol_by_after_aliases)
141
142 # Step 3: Negate symbols only in "before" (being careful with aliases).
143 removed = []
144 negated_symbol_by_before_aliases = {}
145 for remaining_syms in before_symbols_by_key.itervalues():
146 removed.extend(_NegateAndClone(remaining_syms, matched_before_aliases,
147 negated_symbol_by_before_aliases))
148
149 # Step 4: Create ** symbols to represent padding differences.
150 for section_name, padding in padding_by_section_name.iteritems():
151 if padding != 0:
152 similar.append(models.Symbol(
153 section_name, padding,
154 name="** aggregate padding of diff'ed symbols"))
155 return models.SymbolDiff(
156 added, removed, similar, name=after.name, full_name=after.full_name,
157 section_name=after.section_name)
158
159
160 def Diff(before, after):
161 """Diffs two SizeInfo or SymbolGroup objects.
162
163 When diffing SizeInfos, a SizeInfoDiff is returned.
164 When diffing SymbolGroups, a SymbolDiff is returned.
165
166 Returns:
167 Returns a SizeInfo when args are of type SizeInfo.
168 Returns a SymbolDiff when args are of type SymbolGroup.
169 """
170 if isinstance(after, models.SizeInfo):
171 assert isinstance(before, models.SizeInfo)
172 section_sizes = {k: after.section_sizes[k] - v
173 for k, v in before.section_sizes.iteritems()}
174 symbol_diff = _DiffSymbolGroups(before.symbols, after.symbols)
175 return models.SizeInfoDiff(section_sizes, symbol_diff, before.metadata,
176 after.metadata)
177
178 assert (isinstance(after, models.SymbolGroup) and
179 isinstance(before, models.SymbolGroup))
180 return _DiffSymbolGroups(before, after)
181
182
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