| 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 """Methods for converting model objects to human-readable formats.""" | 4 """Methods for converting model objects to human-readable formats.""" |
| 5 | 5 |
| 6 import datetime | 6 import datetime |
| 7 import itertools | 7 import itertools |
| 8 import time | 8 import time |
| 9 | 9 |
| 10 import models | 10 import models |
| (...skipping 11 matching lines...) Expand all Loading... |
| 22 return '%.1fkb' % size | 22 return '%.1fkb' % size |
| 23 elif abs(size) < 1024: | 23 elif abs(size) < 1024: |
| 24 return '%dkb' % size | 24 return '%dkb' % size |
| 25 size /= 1024.0 | 25 size /= 1024.0 |
| 26 if abs(size) < 10: | 26 if abs(size) < 10: |
| 27 return '%.2fmb' % size | 27 return '%.2fmb' % size |
| 28 # We shouldn't be seeing sizes > 100mb. | 28 # We shouldn't be seeing sizes > 100mb. |
| 29 return '%.1fmb' % size | 29 return '%.1fmb' % size |
| 30 | 30 |
| 31 | 31 |
| 32 def _FormatPss(pss): |
| 33 # Shows a decimal for small numbers to make it clear that a shared symbol has |
| 34 # a non-zero pss. |
| 35 if pss > 10: |
| 36 return str(int(pss)) |
| 37 ret = str(round(pss, 1)) |
| 38 if ret.endswith('.0'): |
| 39 ret = ret[:-2] |
| 40 return ret |
| 41 |
| 42 |
| 32 def _DiffPrefix(diff, sym): | 43 def _DiffPrefix(diff, sym): |
| 33 if diff.IsAdded(sym): | 44 if diff.IsAdded(sym): |
| 34 return '+ ' | 45 return '+ ' |
| 35 if diff.IsRemoved(sym): | 46 if diff.IsRemoved(sym): |
| 36 return '- ' | 47 return '- ' |
| 37 if sym.size: | 48 if sym.size: |
| 38 return '~ ' | 49 return '~ ' |
| 39 return '= ' | 50 return '= ' |
| 40 | 51 |
| 41 | 52 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 61 yield ' {}: {:,} bytes ({:.1%})'.format(name, size, percent) | 72 yield ' {}: {:,} bytes ({:.1%})'.format(name, size, percent) |
| 62 | 73 |
| 63 if self.verbose: | 74 if self.verbose: |
| 64 yield '' | 75 yield '' |
| 65 yield 'Other section sizes:' | 76 yield 'Other section sizes:' |
| 66 section_names = sorted(k for k in section_sizes.iterkeys() | 77 section_names = sorted(k for k in section_sizes.iterkeys() |
| 67 if k not in section_names) | 78 if k not in section_names) |
| 68 for name in section_names: | 79 for name in section_names: |
| 69 yield ' {}: {:,} bytes'.format(name, section_sizes[name]) | 80 yield ' {}: {:,} bytes'.format(name, section_sizes[name]) |
| 70 | 81 |
| 71 def _DescribeSymbol(self, sym): | 82 def _DescribeSymbol(self, sym, single_line=False): |
| 72 if sym.IsGroup(): | 83 if sym.IsGroup(): |
| 73 address = 'Group' | 84 address = 'Group' |
| 74 else: | 85 else: |
| 75 address = hex(sym.address) | 86 address = hex(sym.address) |
| 76 if self.verbose: | 87 if self.verbose: |
| 77 count_part = ' count=%d' % len(sym) if sym.IsGroup() else '' | 88 count_part = ' count=%d' % len(sym) if sym.IsGroup() else '' |
| 78 yield '{}@{:<9s} pss={} padding={} size_without_padding={}{}'.format( | 89 yield '{}@{:<9s} pss={} padding={} size_without_padding={}{}'.format( |
| 79 sym.section, address, int(sym.pss), sym.padding, | 90 sym.section, address, _FormatPss(sym.pss), sym.padding, |
| 80 sym.size_without_padding, count_part) | 91 sym.size_without_padding, count_part) |
| 81 yield ' source_path={} \tobject_path={}'.format( | 92 yield ' source_path={} \tobject_path={}'.format( |
| 82 sym.source_path, sym.object_path) | 93 sym.source_path, sym.object_path) |
| 83 if sym.name: | 94 if sym.name: |
| 84 yield ' flags={} name={}'.format(sym.FlagsString(), sym.name) | 95 yield ' flags={} name={}'.format(sym.FlagsString(), sym.name) |
| 85 if sym.full_name: | 96 if sym.full_name: |
| 86 yield ' full_name={}'.format(sym.full_name) | 97 yield ' full_name={}'.format(sym.full_name) |
| 87 elif sym.full_name: | 98 elif sym.full_name: |
| 88 yield ' flags={} full_name={}'.format( | 99 yield ' flags={} full_name={}'.format( |
| 89 sym.FlagsString(), sym.full_name) | 100 sym.FlagsString(), sym.full_name) |
| 101 elif single_line: |
| 102 count_part = ' (count=%d)' % len(sym) if sym.IsGroup() else '' |
| 103 yield '{}@{:<9s} {:<7} {}{}'.format( |
| 104 sym.section, address, _FormatPss(sym.pss), sym.name, count_part) |
| 90 else: | 105 else: |
| 91 yield '{}@{:<9s} {:<7} {}'.format( | 106 yield '{}@{:<9s} {:<7} {}'.format( |
| 92 sym.section, address, int(sym.pss), | 107 sym.section, address, _FormatPss(sym.pss), |
| 93 sym.source_path or sym.object_path or '{no path}') | 108 sym.source_path or sym.object_path or '{no path}') |
| 94 if sym.name: | 109 if sym.name: |
| 95 count_part = ' (count=%d)' % len(sym) if sym.IsGroup() else '' | 110 count_part = ' (count=%d)' % len(sym) if sym.IsGroup() else '' |
| 96 yield ' {}{}'.format(sym.name, count_part) | 111 yield ' {}{}'.format(sym.name, count_part) |
| 97 | 112 |
| 98 def _DescribeSymbolGroupChildren(self, group, indent=0): | 113 def _DescribeSymbolGroupChildren(self, group, indent=0): |
| 99 running_total = 0 | 114 running_total = 0 |
| 100 sorted_syms = group if group.is_sorted else group.Sorted() | 115 running_percent = 0 |
| 101 is_diff = isinstance(group, models.SymbolDiff) | 116 is_diff = isinstance(group, models.SymbolDiff) |
| 117 all_groups = all(s.IsGroup() for s in group) |
| 102 | 118 |
| 103 indent_prefix = '> ' * indent | 119 indent_prefix = '> ' * indent |
| 104 diff_prefix = '' | 120 diff_prefix = '' |
| 105 for s in sorted_syms: | 121 total = group.pss |
| 122 for index, s in enumerate(group): |
| 106 if group.IsBss() or not s.IsBss(): | 123 if group.IsBss() or not s.IsBss(): |
| 107 running_total += s.pss | 124 running_total += s.pss |
| 108 for l in self._DescribeSymbol(s): | 125 running_percent = running_total / total |
| 126 for l in self._DescribeSymbol(s, single_line=all_groups): |
| 109 if l[:4].isspace(): | 127 if l[:4].isspace(): |
| 110 indent_size = 8 + len(indent_prefix) + len(diff_prefix) | 128 indent_size = 8 + len(indent_prefix) + len(diff_prefix) |
| 111 yield '{} {}'.format(' ' * indent_size, l) | 129 yield '{} {}'.format(' ' * indent_size, l) |
| 112 else: | 130 else: |
| 113 if is_diff: | 131 if is_diff: |
| 114 diff_prefix = _DiffPrefix(group, s) | 132 diff_prefix = _DiffPrefix(group, s) |
| 115 yield '{}{}{:8} {}'.format(indent_prefix, diff_prefix, | 133 yield '{}{}{:<4} {:>8} {:7} {}'.format( |
| 116 int(running_total), l) | 134 indent_prefix, diff_prefix, str(index) + ')', |
| 135 _FormatPss(running_total), '({:.1%})'.format(running_percent), l) |
| 117 | 136 |
| 118 if self.recursive and s.IsGroup(): | 137 if self.recursive and s.IsGroup(): |
| 119 for l in self._DescribeSymbolGroupChildren(s, indent=indent + 1): | 138 for l in self._DescribeSymbolGroupChildren(s, indent=indent + 1): |
| 120 yield l | 139 yield l |
| 121 | 140 |
| 122 def _DescribeSymbolGroup(self, group): | 141 def _DescribeSymbolGroup(self, group): |
| 123 total_size = group.pss | 142 total_size = group.pss |
| 124 code_syms = group.WhereInSection('t') | 143 code_size = 0 |
| 125 code_size = code_syms.pss | 144 ro_size = 0 |
| 126 ro_size = code_syms.Inverted().WhereInSection('r').pss | 145 unique_paths = set() |
| 127 unique_paths = set(s.object_path for s in group) | 146 for s in group.IterLeafSymbols(): |
| 147 if s.section == 't': |
| 148 code_size += s.pss |
| 149 elif s.section == 'r': |
| 150 ro_size += s.pss |
| 151 unique_paths.add(s.object_path) |
| 128 header_desc = [ | 152 header_desc = [ |
| 129 'Showing {:,} symbols ({:,} unique) with total pss: {} bytes'.format( | 153 'Showing {:,} symbols ({:,} unique) with total pss: {} bytes'.format( |
| 130 len(group), group.CountUniqueSymbols(), int(total_size)), | 154 len(group), group.CountUniqueSymbols(), int(total_size)), |
| 131 '.text={:<10} .rodata={:<10} other={:<10} total={}'.format( | 155 '.text={:<10} .rodata={:<10} other={:<10} total={}'.format( |
| 132 _PrettySize(int(code_size)), _PrettySize(int(ro_size)), | 156 _PrettySize(int(code_size)), _PrettySize(int(ro_size)), |
| 133 _PrettySize(int(total_size - code_size - ro_size)), | 157 _PrettySize(int(total_size - code_size - ro_size)), |
| 134 _PrettySize(int(total_size))), | 158 _PrettySize(int(total_size))), |
| 135 'Number of object files: {}'.format(len(unique_paths)), | 159 'Number of object files: {}'.format(len(unique_paths)), |
| 136 '', | 160 '', |
| 137 'First columns are: running total, address, pss', | 161 'Index, Running Total, Section@Address, PSS', |
| 162 '-' * 60 |
| 138 ] | 163 ] |
| 139 children_desc = self._DescribeSymbolGroupChildren(group) | 164 children_desc = self._DescribeSymbolGroupChildren(group) |
| 140 return itertools.chain(header_desc, children_desc) | 165 return itertools.chain(header_desc, children_desc) |
| 141 | 166 |
| 142 def _DescribeSymbolDiff(self, diff): | 167 def _DescribeSymbolDiff(self, diff): |
| 143 header_template = ('{} symbols added (+), {} changed (~), {} removed (-), ' | 168 header_template = ('{} symbols added (+), {} changed (~), {} removed (-), ' |
| 144 '{} unchanged ({})') | 169 '{} unchanged ({})') |
| 145 unchanged_msg = '=' if self.verbose else 'not shown' | 170 unchanged_msg = '=' if self.verbose else 'not shown' |
| 146 symbol_delta_desc = [header_template.format( | 171 symbol_delta_desc = [header_template.format( |
| 147 diff.added_count, diff.changed_count, diff.removed_count, | 172 diff.added_count, diff.changed_count, diff.removed_count, |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 291 | 316 |
| 292 def GenerateLines(obj, verbose=False, recursive=False): | 317 def GenerateLines(obj, verbose=False, recursive=False): |
| 293 """Returns an iterable of lines (without \n) that describes |obj|.""" | 318 """Returns an iterable of lines (without \n) that describes |obj|.""" |
| 294 return Describer(verbose=verbose, recursive=recursive).GenerateLines(obj) | 319 return Describer(verbose=verbose, recursive=recursive).GenerateLines(obj) |
| 295 | 320 |
| 296 | 321 |
| 297 def WriteLines(lines, func): | 322 def WriteLines(lines, func): |
| 298 for l in lines: | 323 for l in lines: |
| 299 func(l) | 324 func(l) |
| 300 func('\n') | 325 func('\n') |
| OLD | NEW |