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

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

Issue 2851473003: supersize: Track symbol aliases and shared symbols (Closed)
Patch Set: tweak nm interfface 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]
estevenson 2017/04/28 17:06:11 Already forgot - what does this mean again?
agrieve 2017/04/28 19:26:59 Comment added.
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): Diff logic does not work correctly when aliased symbols span
106 # mulitple groups. We should simplify by not allowing recursion (allow diffs
107 # only on SizeInfo, apply logic to raw_symbols, re-cluster after-the-fact.
108 def _DiffSymbolGroups(before, after):
109 before_symbols_by_key = collections.defaultdict(list)
110 for s in before:
111 before_symbols_by_key[s._Key()].append(s)
112
113 similar = []
114 diffed_symbol_by_after_aliases = {}
115 matched_before_aliases = set()
116 unmatched_after_syms = []
117 # For similar symbols, padding is zeroed out. In order to not lose the
118 # information entirely, store it in aggregate.
119 padding_by_section_name = collections.defaultdict(int)
120
121 # Step 1: Create all delta symbols and record unmatched symbols.
122 for after_sym in after:
123 matching_syms = before_symbols_by_key.get(after_sym._Key())
124 if matching_syms:
125 before_sym = matching_syms.pop(0)
126 if before_sym.IsGroup() and after_sym.IsGroup():
127 similar.append(_DiffSymbolGroups(before_sym, after_sym))
128 else:
129 if before_sym.aliases:
130 matched_before_aliases.add(id(before_sym.aliases))
131 similar.append(
132 _DiffSymbol(before_sym, after_sym, diffed_symbol_by_after_aliases,
133 padding_by_section_name))
134 else:
135 unmatched_after_syms.append(after_sym)
136 continue
137
138 # Step 2: Copy symbols only in "after" (being careful with aliases).
139 added = _CloneUnmatched(unmatched_after_syms, diffed_symbol_by_after_aliases)
140
141 # Step 3: Negate symbols only in "before" (being careful with aliases).
142 removed = []
143 negated_symbol_by_before_aliases = {}
144 for remaining_syms in before_symbols_by_key.itervalues():
145 removed.extend(_NegateAndClone(remaining_syms, matched_before_aliases,
146 negated_symbol_by_before_aliases))
147
148 # Step 4: Create ** symbols to represent padding differences.
149 for section_name, padding in padding_by_section_name.iteritems():
150 if padding != 0:
151 similar.append(models.Symbol(
152 section_name, padding,
153 name="** aggregate padding of diff'ed symbols"))
154 return models.SymbolDiff(
155 added, removed, similar, name=after.name, full_name=after.full_name,
156 section_name=after.section_name)
157
158
159 def Diff(before, after):
160 """Diffs two SizeInfo or SymbolGroup objects.
161
162 When diffing SizeInfos, a SizeInfoDiff is returned.
163 When diffing SymbolGroups, a SymbolDiff is returned.
164
165 Returns:
166 Returns a SizeInfo when args are of type SizeInfo.
167 Returns a SymbolDiff when args are of type SymbolGroup.
168 """
169 if isinstance(after, models.SizeInfo):
170 assert isinstance(before, models.SizeInfo)
171 section_sizes = {k: after.section_sizes[k] - v
172 for k, v in before.section_sizes.iteritems()}
173 symbol_diff = _DiffSymbolGroups(before.symbols, after.symbols)
174 return models.SizeInfoDiff(section_sizes, symbol_diff, before.metadata,
175 after.metadata)
176
177 assert (isinstance(after, models.SymbolGroup) and
178 isinstance(before, models.SymbolGroup))
179 return _DiffSymbolGroups(before, after)
180
181
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698