OLD | NEW |
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 | 7 |
8 import models | 8 import models |
9 | 9 |
10 | 10 |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
50 | 50 |
51 # If this is the first matched symbol of an alias group, initialize its | 51 # If this is the first matched symbol of an alias group, initialize its |
52 # aliases list. The remaining aliases will be appended when diff'ed. | 52 # aliases list. The remaining aliases will be appended when diff'ed. |
53 if after_sym.aliases: | 53 if after_sym.aliases: |
54 ret.aliases = [ret] | 54 ret.aliases = [ret] |
55 diffed_symbol_by_after_aliases[id(after_sym.aliases)] = ret | 55 diffed_symbol_by_after_aliases[id(after_sym.aliases)] = ret |
56 return ret | 56 return ret |
57 | 57 |
58 | 58 |
59 def _CloneUnmatched(after_symbols, diffed_symbol_by_after_aliases): | 59 def _CloneUnmatched(after_symbols, diffed_symbol_by_after_aliases): |
60 ret = [] | 60 ret = [None] * len(after_symbols) |
61 for sym in after_symbols: | 61 for i, sym in enumerate(after_symbols): |
62 cloned = sym | 62 cloned = sym |
63 if sym.IsGroup(): | 63 if sym.aliases: |
64 cloned = models.SymbolDiff( | |
65 [], _CloneUnmatched(sym, diffed_symbol_by_after_aliases), [], | |
66 name=sym.name, full_name=sym.full_name, section_name=sym.section_name) | |
67 elif sym.aliases: | |
68 diffed_alias = diffed_symbol_by_after_aliases.get(id(sym.aliases)) | 64 diffed_alias = diffed_symbol_by_after_aliases.get(id(sym.aliases)) |
69 if diffed_alias: | 65 if diffed_alias: |
70 # At least one alias was diffed. | 66 # At least one alias was diffed. |
71 cloned = _CloneAlias(sym, diffed_alias) | 67 cloned = _CloneAlias(sym, diffed_alias) |
72 ret.append(cloned) | 68 ret[i] = cloned |
73 return ret | 69 return ret |
74 | 70 |
75 | 71 |
76 def _NegateAndClone(before_symbols, matched_before_aliases, | 72 def _NegateAndClone(before_symbols, matched_before_aliases, |
77 negated_symbol_by_before_aliases): | 73 negated_symbol_by_before_aliases): |
78 ret = [] | 74 ret = [None] * len(before_symbols) |
79 for sym in before_symbols: | 75 for i, sym in enumerate(before_symbols): |
80 if sym.IsGroup(): | 76 if sym.aliases: |
81 cloned = models.SymbolDiff( | 77 negated_alias = negated_symbol_by_before_aliases.get(id(sym.aliases)) |
82 [], _NegateAndClone(sym, matched_before_aliases, | 78 if negated_alias: |
83 negated_symbol_by_before_aliases), [], | 79 cloned = _CloneAlias(sym, negated_alias) |
84 name=sym.name, full_name=sym.full_name, section_name=sym.section_name) | 80 else: |
| 81 all_aliases_removed = id(sym.aliases) not in matched_before_aliases |
| 82 # If all alises are removed, then given them negative size to reflect |
| 83 # the savings. |
| 84 if all_aliases_removed: |
| 85 cloned = _CloneSymbol(sym, -sym.size_without_padding) |
| 86 cloned.padding = -sym.padding |
| 87 else: |
| 88 # But if only a subset of aliases are removed, do not actually treat |
| 89 # them as aliases anymore, or else they will weigh down the PSS of |
| 90 # the symbols that were not removed. |
| 91 cloned = _CloneSymbol(sym, 0) |
| 92 cloned.aliases = [cloned] |
| 93 negated_symbol_by_before_aliases[id(sym.aliases)] = cloned |
85 else: | 94 else: |
86 negated_alias = None | 95 cloned = _CloneSymbol(sym, -sym.size_without_padding) |
87 if sym.aliases: | 96 cloned.padding = -sym.padding |
88 negated_alias = negated_symbol_by_before_aliases.get(id(sym.aliases)) | 97 ret[i] = cloned |
89 if negated_alias: | |
90 cloned = _CloneAlias(sym, negated_alias) | |
91 else: | |
92 all_aliases_removed = id(sym.aliases) not in matched_before_aliases | |
93 # If all alises are removed, then given them negative size to reflect | |
94 # the savings. | |
95 if all_aliases_removed: | |
96 cloned = _CloneSymbol(sym, -sym.size_without_padding) | |
97 cloned.padding = -sym.padding | |
98 else: | |
99 # But if only a subset of aliases are removed, do not actually treat | |
100 # them as aliases anymore, or else they will weigh down the PSS of | |
101 # the symbols that were not removed. | |
102 cloned = _CloneSymbol(sym, 0) | |
103 cloned.aliases = [cloned] | |
104 negated_symbol_by_before_aliases[id(sym.aliases)] = cloned | |
105 else: | |
106 cloned = _CloneSymbol(sym, -sym.size_without_padding) | |
107 cloned.padding = -sym.padding | |
108 ret.append(cloned) | |
109 return ret | 98 return ret |
110 | 99 |
111 | 100 |
112 # TODO(agrieve): Diff logic does not work correctly when aliased symbols span | |
113 # mulitple groups. We should simplify by not allowing recursion (allow diffs | |
114 # only on SizeInfo, apply logic to raw_symbols, re-cluster after-the-fact. | |
115 def _DiffSymbolGroups(before, after): | 101 def _DiffSymbolGroups(before, after): |
116 before_symbols_by_key = collections.defaultdict(list) | 102 before_symbols_by_key = collections.defaultdict(list) |
117 for s in before: | 103 for s in before: |
118 before_symbols_by_key[s._Key()].append(s) | 104 before_symbols_by_key[s._Key()].append(s) |
119 | 105 |
120 similar = [] | 106 similar = [] |
121 diffed_symbol_by_after_aliases = {} | 107 diffed_symbol_by_after_aliases = {} |
122 matched_before_aliases = set() | 108 matched_before_aliases = set() |
123 unmatched_after_syms = [] | 109 unmatched_after_syms = [] |
124 # For similar symbols, padding is zeroed out. In order to not lose the | 110 # For similar symbols, padding is zeroed out. In order to not lose the |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
156 for section_name, padding in padding_by_section_name.iteritems(): | 142 for section_name, padding in padding_by_section_name.iteritems(): |
157 if padding != 0: | 143 if padding != 0: |
158 similar.append(models.Symbol( | 144 similar.append(models.Symbol( |
159 section_name, padding, | 145 section_name, padding, |
160 name="** aggregate padding of diff'ed symbols")) | 146 name="** aggregate padding of diff'ed symbols")) |
161 return models.SymbolDiff( | 147 return models.SymbolDiff( |
162 added, removed, similar, name=after.name, full_name=after.full_name, | 148 added, removed, similar, name=after.name, full_name=after.full_name, |
163 section_name=after.section_name) | 149 section_name=after.section_name) |
164 | 150 |
165 | 151 |
166 def Diff(before, after): | 152 def Diff(before, after, cluster=True): |
167 """Diffs two SizeInfo or SymbolGroup objects. | 153 """Diffs two SizeInfo objects. Returns a SizeInfoDiff. |
168 | 154 |
169 When diffing SizeInfos, a SizeInfoDiff is returned. | 155 Args: |
170 When diffing SymbolGroups, a SymbolDiff is returned. | 156 cluster: When True, calls SymbolGroup.Cluster() after diffing. This |
171 | 157 generally reduces noise. |
172 Returns: | |
173 Returns a SizeInfo when args are of type SizeInfo. | |
174 Returns a SymbolDiff when args are of type SymbolGroup. | |
175 """ | 158 """ |
176 if isinstance(after, models.SizeInfo): | 159 assert isinstance(before, models.SizeInfo) |
177 assert isinstance(before, models.SizeInfo) | 160 assert isinstance(after, models.SizeInfo) |
178 section_sizes = {k: after.section_sizes[k] - v | 161 section_sizes = {k: after.section_sizes[k] - v |
179 for k, v in before.section_sizes.iteritems()} | 162 for k, v in before.section_sizes.iteritems()} |
180 symbol_diff = _DiffSymbolGroups(before.symbols, after.symbols) | 163 symbol_diff = _DiffSymbolGroups(before.symbols, after.symbols) |
181 return models.SizeInfoDiff(section_sizes, symbol_diff, before.metadata, | 164 if cluster: |
182 after.metadata) | 165 symbol_diff = symbol_diff.Cluster() |
183 | 166 return models.SizeInfoDiff(section_sizes, symbol_diff, before.metadata, |
184 assert (isinstance(after, models.SymbolGroup) and | 167 after.metadata) |
185 isinstance(before, models.SymbolGroup)) | |
186 return _DiffSymbolGroups(before, after) | |
187 | |
188 | |
OLD | NEW |