| 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 Some notes on common propertis: | 8 Some notes on common propertis: |
| 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 15 matching lines...) Expand all Loading... |
| 26 | 26 |
| 27 import collections | 27 import collections |
| 28 import copy | 28 import copy |
| 29 import os | 29 import os |
| 30 import re | 30 import re |
| 31 | 31 |
| 32 import match_util | 32 import match_util |
| 33 | 33 |
| 34 | 34 |
| 35 METADATA_GIT_REVISION = 'git_revision' | 35 METADATA_GIT_REVISION = 'git_revision' |
| 36 METADATA_MAP_FILENAME = 'map_file_name' | 36 METADATA_MAP_FILENAME = 'map_file_name' # Path relative to output_directory. |
| 37 METADATA_ELF_FILENAME = 'elf_file_name' | 37 METADATA_ELF_FILENAME = 'elf_file_name' # Path relative to output_directory. |
| 38 METADATA_ELF_MTIME = 'elf_mtime' # int timestamp in utc. | 38 METADATA_ELF_MTIME = 'elf_mtime' # int timestamp in utc. |
| 39 METADATA_ELF_BUILD_ID = 'elf_build_id' | 39 METADATA_ELF_BUILD_ID = 'elf_build_id' |
| 40 METADATA_GN_ARGS = 'gn_args' |
| 41 |
| 40 | 42 |
| 41 SECTION_TO_SECTION_NAME = { | 43 SECTION_TO_SECTION_NAME = { |
| 42 'b': '.bss', | 44 'b': '.bss', |
| 43 'd': '.data', | 45 'd': '.data', |
| 44 'r': '.rodata', | 46 'r': '.rodata', |
| 45 't': '.text', | 47 't': '.text', |
| 46 } | 48 } |
| 47 | 49 |
| 48 | 50 |
| 49 class SizeInfo(object): | 51 class SizeInfo(object): |
| 50 """Represents all size information for a single binary. | 52 """Represents all size information for a single binary. |
| 51 | 53 |
| 52 Fields: | 54 Fields: |
| 53 section_sizes: A dict of section_name -> size. | 55 section_sizes: A dict of section_name -> size. |
| 54 symbols: A SymbolGroup (or SymbolDiff) with all symbols in it. | 56 symbols: A SymbolGroup with all symbols in it. |
| 55 metadata: A dict. | 57 metadata: A dict. |
| 56 """ | 58 """ |
| 57 __slots__ = ( | 59 __slots__ = ( |
| 58 'section_sizes', | 60 'section_sizes', |
| 59 'symbols', | 61 'symbols', |
| 60 'metadata', | 62 'metadata', |
| 61 ) | 63 ) |
| 62 | 64 |
| 63 """Root size information.""" | 65 """Root size information.""" |
| 64 def __init__(self, section_sizes, symbols, metadata=None): | 66 def __init__(self, section_sizes, symbols, metadata=None): |
| 65 self.section_sizes = section_sizes # E.g. {'.text': 0} | 67 self.section_sizes = section_sizes # E.g. {'.text': 0} |
| 66 self.symbols = symbols # List of symbols sorted by address per-section. | 68 self.symbols = symbols # List of symbols sorted by address per-section. |
| 67 self.metadata = metadata or {} | 69 self.metadata = metadata or {} |
| 68 | 70 |
| 69 | 71 |
| 72 class SizeInfoDiff(object): |
| 73 """What you get when you Diff() two SizeInfo objects. |
| 74 |
| 75 Fields: |
| 76 section_sizes: A dict of section_name -> size delta. |
| 77 symbols: A SymbolDiff with all symbols in it. |
| 78 old_metadata: metadata of the "old" SizeInfo. |
| 79 new_metadata: metadata of the "new" SizeInfo. |
| 80 """ |
| 81 __slots__ = ( |
| 82 'section_sizes', |
| 83 'symbols', |
| 84 'old_metadata', |
| 85 'new_metadata', |
| 86 ) |
| 87 |
| 88 def __init__(self, section_sizes, symbols, old_metadata, new_metadata): |
| 89 self.section_sizes = section_sizes |
| 90 self.symbols = symbols |
| 91 self.old_metadata = old_metadata |
| 92 self.new_metadata = new_metadata |
| 93 |
| 94 |
| 70 class BaseSymbol(object): | 95 class BaseSymbol(object): |
| 71 """Base class for Symbol and SymbolGroup. | 96 """Base class for Symbol and SymbolGroup. |
| 72 | 97 |
| 73 Refer to module docs for field descriptions. | 98 Refer to module docs for field descriptions. |
| 74 """ | 99 """ |
| 75 __slots__ = () | 100 __slots__ = () |
| 76 | 101 |
| 77 @property | 102 @property |
| 78 def section(self): | 103 def section(self): |
| 79 """Returns the one-letter section. | 104 """Returns the one-letter section. |
| (...skipping 462 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 542 def IsRemoved(self, sym): | 567 def IsRemoved(self, sym): |
| 543 return id(sym) in self._removed_ids | 568 return id(sym) in self._removed_ids |
| 544 | 569 |
| 545 def WhereNotUnchanged(self): | 570 def WhereNotUnchanged(self): |
| 546 return self.Filter(lambda s: not self.IsSimilar(s) or s.size) | 571 return self.Filter(lambda s: not self.IsSimilar(s) or s.size) |
| 547 | 572 |
| 548 | 573 |
| 549 def Diff(new, old): | 574 def Diff(new, old): |
| 550 """Diffs two SizeInfo or SymbolGroup objects. | 575 """Diffs two SizeInfo or SymbolGroup objects. |
| 551 | 576 |
| 552 When diffing SizeInfos, ret.section_sizes are the result of |new| - |old|, and | 577 When diffing SizeInfos, a SizeInfoDiff is returned. |
| 553 ret.symbols will be a SymbolDiff. | |
| 554 | |
| 555 When diffing SymbolGroups, a SymbolDiff is returned. | 578 When diffing SymbolGroups, a SymbolDiff is returned. |
| 556 | 579 |
| 557 Returns: | 580 Returns: |
| 558 Returns a SizeInfo when args are of type SizeInfo. | 581 Returns a SizeInfo when args are of type SizeInfo. |
| 559 Returns a SymbolDiff when args are of type SymbolGroup. | 582 Returns a SymbolDiff when args are of type SymbolGroup. |
| 560 """ | 583 """ |
| 561 if isinstance(new, SizeInfo): | 584 if isinstance(new, SizeInfo): |
| 562 assert isinstance(old, SizeInfo) | 585 assert isinstance(old, SizeInfo) |
| 563 section_sizes = { | 586 section_sizes = { |
| 564 k:new.section_sizes[k] - v for k, v in old.section_sizes.iteritems()} | 587 k:new.section_sizes[k] - v for k, v in old.section_sizes.iteritems()} |
| 565 symbol_diff = Diff(new.symbols, old.symbols) | 588 symbol_diff = Diff(new.symbols, old.symbols) |
| 566 return SizeInfo(section_sizes, symbol_diff) | 589 return SizeInfoDiff(section_sizes, symbol_diff, old.metadata, new.metadata) |
| 567 | 590 |
| 568 assert isinstance(new, SymbolGroup) and isinstance(old, SymbolGroup) | 591 assert isinstance(new, SymbolGroup) and isinstance(old, SymbolGroup) |
| 569 symbols_by_key = collections.defaultdict(list) | 592 symbols_by_key = collections.defaultdict(list) |
| 570 for s in old: | 593 for s in old: |
| 571 symbols_by_key[s._Key()].append(s) | 594 symbols_by_key[s._Key()].append(s) |
| 572 | 595 |
| 573 added = [] | 596 added = [] |
| 574 removed = [] | 597 removed = [] |
| 575 similar = [] | 598 similar = [] |
| 576 # For similar symbols, padding is zeroed out. In order to not lose the | 599 # For similar symbols, padding is zeroed out. In order to not lose the |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 610 | 633 |
| 611 def _ExtractPrefixBeforeSeparator(string, separator, count=1): | 634 def _ExtractPrefixBeforeSeparator(string, separator, count=1): |
| 612 idx = -len(separator) | 635 idx = -len(separator) |
| 613 prev_idx = None | 636 prev_idx = None |
| 614 for _ in xrange(count): | 637 for _ in xrange(count): |
| 615 idx = string.find(separator, idx + len(separator)) | 638 idx = string.find(separator, idx + len(separator)) |
| 616 if idx < 0: | 639 if idx < 0: |
| 617 break | 640 break |
| 618 prev_idx = idx | 641 prev_idx = idx |
| 619 return string[:prev_idx] | 642 return string[:prev_idx] |
| OLD | NEW |