| 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 """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 29 matching lines...) Expand all Loading... |
| 40 METADATA_GN_ARGS = 'gn_args' | 40 METADATA_GN_ARGS = 'gn_args' |
| 41 | 41 |
| 42 | 42 |
| 43 SECTION_TO_SECTION_NAME = { | 43 SECTION_TO_SECTION_NAME = { |
| 44 'b': '.bss', | 44 'b': '.bss', |
| 45 'd': '.data', | 45 'd': '.data', |
| 46 'r': '.rodata', | 46 'r': '.rodata', |
| 47 't': '.text', | 47 't': '.text', |
| 48 } | 48 } |
| 49 | 49 |
| 50 FLAG_ANONYMOUS = 1 |
| 51 FLAG_STARTUP = 2 |
| 52 FLAG_UNLIKELY = 4 |
| 53 FLAG_REL = 8 |
| 54 FLAG_REL_LOCAL = 16 |
| 55 |
| 50 | 56 |
| 51 class SizeInfo(object): | 57 class SizeInfo(object): |
| 52 """Represents all size information for a single binary. | 58 """Represents all size information for a single binary. |
| 53 | 59 |
| 54 Fields: | 60 Fields: |
| 55 section_sizes: A dict of section_name -> size. | 61 section_sizes: A dict of section_name -> size. |
| 56 raw_symbols: A flat list of all symbols. | 62 raw_symbols: A flat list of all symbols. |
| 57 symbols: A SymbolGroup containing raw_symbols, but with some Symbols grouped | 63 symbols: A SymbolGroup containing raw_symbols, but with some Symbols grouped |
| 58 into sub-SymbolGroups. | 64 into sub-SymbolGroups. |
| 59 metadata: A dict. | 65 metadata: A dict. |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 115 return self.section_name[1] | 121 return self.section_name[1] |
| 116 | 122 |
| 117 @property | 123 @property |
| 118 def size_without_padding(self): | 124 def size_without_padding(self): |
| 119 return self.size - self.padding | 125 return self.size - self.padding |
| 120 | 126 |
| 121 @property | 127 @property |
| 122 def end_address(self): | 128 def end_address(self): |
| 123 return self.address + self.size_without_padding | 129 return self.address + self.size_without_padding |
| 124 | 130 |
| 131 @property |
| 132 def is_anonymous(self): |
| 133 return bool(self.flags & FLAG_ANONYMOUS) |
| 134 |
| 135 def FlagsString(self): |
| 136 # Most flags are 0. |
| 137 flags = self.flags |
| 138 if not flags: |
| 139 return '{}' |
| 140 parts = [] |
| 141 if flags & FLAG_ANONYMOUS: |
| 142 parts.append('anon') |
| 143 if flags & FLAG_STARTUP: |
| 144 parts.append('startup') |
| 145 if flags & FLAG_UNLIKELY: |
| 146 parts.append('unlikely') |
| 147 if flags & FLAG_REL: |
| 148 parts.append('rel') |
| 149 if flags & FLAG_REL_LOCAL: |
| 150 parts.append('rel.loc') |
| 151 return '{%s}' % ','.join(parts) |
| 152 |
| 125 def IsBss(self): | 153 def IsBss(self): |
| 126 return self.section_name == '.bss' | 154 return self.section_name == '.bss' |
| 127 | 155 |
| 128 def IsGroup(self): | 156 def IsGroup(self): |
| 129 return False | 157 return False |
| 130 | 158 |
| 131 def IsGenerated(self): | 159 def IsGenerated(self): |
| 132 # TODO(agrieve): Also match generated functions such as: | 160 # TODO(agrieve): Also match generated functions such as: |
| 133 # startup._GLOBAL__sub_I_page_allocator.cc | 161 # startup._GLOBAL__sub_I_page_allocator.cc |
| 134 return self.name.endswith(']') and not self.name.endswith('[]') | 162 return self.name.endswith(']') and not self.name.endswith('[]') |
| (...skipping 14 matching lines...) Expand all Loading... |
| 149 | 177 |
| 150 class Symbol(BaseSymbol): | 178 class Symbol(BaseSymbol): |
| 151 """Represents a single symbol within a binary. | 179 """Represents a single symbol within a binary. |
| 152 | 180 |
| 153 Refer to module docs for field descriptions. | 181 Refer to module docs for field descriptions. |
| 154 """ | 182 """ |
| 155 | 183 |
| 156 __slots__ = ( | 184 __slots__ = ( |
| 157 'address', | 185 'address', |
| 158 'full_name', | 186 'full_name', |
| 159 'is_anonymous', | 187 'flags', |
| 160 'object_path', | 188 'object_path', |
| 161 'name', | 189 'name', |
| 162 'padding', | 190 'padding', |
| 163 'section_name', | 191 'section_name', |
| 164 'source_path', | 192 'source_path', |
| 165 'size', | 193 'size', |
| 166 ) | 194 ) |
| 167 | 195 |
| 168 def __init__(self, section_name, size_without_padding, address=None, | 196 def __init__(self, section_name, size_without_padding, address=None, |
| 169 name=None, source_path=None, object_path=None, | 197 name=None, source_path=None, object_path=None, full_name=None, |
| 170 full_name=None, is_anonymous=False): | 198 flags=0): |
| 171 self.section_name = section_name | 199 self.section_name = section_name |
| 172 self.address = address or 0 | 200 self.address = address or 0 |
| 173 self.name = name or '' | 201 self.name = name or '' |
| 174 self.full_name = full_name or '' | 202 self.full_name = full_name or '' |
| 175 self.source_path = source_path or '' | 203 self.source_path = source_path or '' |
| 176 self.object_path = object_path or '' | 204 self.object_path = object_path or '' |
| 177 self.size = size_without_padding | 205 self.size = size_without_padding |
| 178 # Change this to be a bitfield of flags if ever there is a need to add | 206 self.flags = flags |
| 179 # another similar thing. | |
| 180 self.is_anonymous = is_anonymous | |
| 181 self.padding = 0 | 207 self.padding = 0 |
| 182 | 208 |
| 183 def __repr__(self): | 209 def __repr__(self): |
| 184 return ('%s@%x(size_without_padding=%d,padding=%d,name=%s,path=%s,anon=%d)' | 210 return ('%s@%x(size_without_padding=%d,padding=%d,name=%s,path=%s,flags=%s)' |
| 185 % (self.section_name, self.address, self.size_without_padding, | 211 % (self.section_name, self.address, self.size_without_padding, |
| 186 self.padding, self.name, self.source_path or self.object_path, | 212 self.padding, self.name, self.source_path or self.object_path, |
| 187 int(self.is_anonymous))) | 213 self.FlagsString())) |
| 188 | 214 |
| 189 | 215 |
| 190 class SymbolGroup(BaseSymbol): | 216 class SymbolGroup(BaseSymbol): |
| 191 """Represents a group of symbols using the same interface as Symbol. | 217 """Represents a group of symbols using the same interface as Symbol. |
| 192 | 218 |
| 193 SymbolGroups are immutable. All filtering / sorting will return new | 219 SymbolGroups are immutable. All filtering / sorting will return new |
| 194 SymbolGroups objects. | 220 SymbolGroups objects. |
| 195 | 221 |
| 196 Overrides many __functions__. E.g. the following are all valid: | 222 Overrides many __functions__. E.g. the following are all valid: |
| 197 * len(group) | 223 * len(group) |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 262 after_symbols = self._symbols + [s for s in other if id(s) not in self_ids] | 288 after_symbols = self._symbols + [s for s in other if id(s) not in self_ids] |
| 263 return self._CreateTransformed( | 289 return self._CreateTransformed( |
| 264 after_symbols, section_name=self.section_name, is_sorted=False) | 290 after_symbols, section_name=self.section_name, is_sorted=False) |
| 265 | 291 |
| 266 @property | 292 @property |
| 267 def address(self): | 293 def address(self): |
| 268 first = self._symbols[0].address | 294 first = self._symbols[0].address |
| 269 return first if all(s.address == first for s in self._symbols) else 0 | 295 return first if all(s.address == first for s in self._symbols) else 0 |
| 270 | 296 |
| 271 @property | 297 @property |
| 272 def is_anonymous(self): | 298 def flags(self): |
| 273 first = self._symbols[0].is_anonymous | 299 first = self._symbols[0].flags |
| 274 return first if all( | 300 return first if all(s.flags == first for s in self._symbols) else 0 |
| 275 s.is_anonymous == first for s in self._symbols) else False | |
| 276 | 301 |
| 277 @property | 302 @property |
| 278 def object_path(self): | 303 def object_path(self): |
| 279 first = self._symbols[0].object_path | 304 first = self._symbols[0].object_path |
| 280 return first if all(s.object_path == first for s in self._symbols) else None | 305 return first if all(s.object_path == first for s in self._symbols) else None |
| 281 | 306 |
| 282 @property | 307 @property |
| 283 def source_path(self): | 308 def source_path(self): |
| 284 first = self._symbols[0].source_path | 309 first = self._symbols[0].source_path |
| 285 return first if all(s.source_path == first for s in self._symbols) else None | 310 return first if all(s.source_path == first for s in self._symbols) else None |
| (...skipping 358 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 644 if before_sym.IsGroup() and after_sym.IsGroup(): | 669 if before_sym.IsGroup() and after_sym.IsGroup(): |
| 645 merged_sym = _DiffSymbols(before_sym, after_sym) | 670 merged_sym = _DiffSymbols(before_sym, after_sym) |
| 646 else: | 671 else: |
| 647 size_diff = (after_sym.size_without_padding - | 672 size_diff = (after_sym.size_without_padding - |
| 648 before_sym.size_without_padding) | 673 before_sym.size_without_padding) |
| 649 merged_sym = Symbol(after_sym.section_name, size_diff, | 674 merged_sym = Symbol(after_sym.section_name, size_diff, |
| 650 address=after_sym.address, name=after_sym.name, | 675 address=after_sym.address, name=after_sym.name, |
| 651 source_path=after_sym.source_path, | 676 source_path=after_sym.source_path, |
| 652 object_path=after_sym.object_path, | 677 object_path=after_sym.object_path, |
| 653 full_name=after_sym.full_name, | 678 full_name=after_sym.full_name, |
| 654 is_anonymous=after_sym.is_anonymous) | 679 flags=after_sym.flags) |
| 655 | 680 |
| 656 # Diffs are more stable when comparing size without padding, except when | 681 # Diffs are more stable when comparing size without padding, except when |
| 657 # the symbol is a padding-only symbol. | 682 # the symbol is a padding-only symbol. |
| 658 if after_sym.size_without_padding == 0 and size_diff == 0: | 683 if after_sym.size_without_padding == 0 and size_diff == 0: |
| 659 merged_sym.padding = after_sym.padding - before_sym.padding | 684 merged_sym.padding = after_sym.padding - before_sym.padding |
| 660 else: | 685 else: |
| 661 padding_by_section_name[after_sym.section_name] += ( | 686 padding_by_section_name[after_sym.section_name] += ( |
| 662 after_sym.padding - before_sym.padding) | 687 after_sym.padding - before_sym.padding) |
| 663 | 688 |
| 664 similar.append(merged_sym) | 689 similar.append(merged_sym) |
| (...skipping 16 matching lines...) Expand all Loading... |
| 681 | 706 |
| 682 def _ExtractPrefixBeforeSeparator(string, separator, count=1): | 707 def _ExtractPrefixBeforeSeparator(string, separator, count=1): |
| 683 idx = -len(separator) | 708 idx = -len(separator) |
| 684 prev_idx = None | 709 prev_idx = None |
| 685 for _ in xrange(count): | 710 for _ in xrange(count): |
| 686 idx = string.find(separator, idx + len(separator)) | 711 idx = string.find(separator, idx + len(separator)) |
| 687 if idx < 0: | 712 if idx < 0: |
| 688 break | 713 break |
| 689 prev_idx = idx | 714 prev_idx = idx |
| 690 return string[:prev_idx] | 715 return string[:prev_idx] |
| OLD | NEW |