| 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 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 43 def _DiffPrefix(diff, sym): | 43 def _DiffPrefix(diff, sym): |
| 44 if diff.IsAdded(sym): | 44 if diff.IsAdded(sym): |
| 45 return '+ ' | 45 return '+ ' |
| 46 if diff.IsRemoved(sym): | 46 if diff.IsRemoved(sym): |
| 47 return '- ' | 47 return '- ' |
| 48 if sym.size: | 48 if sym.size: |
| 49 return '~ ' | 49 return '~ ' |
| 50 return '= ' | 50 return '= ' |
| 51 | 51 |
| 52 | 52 |
| 53 def _Divide(a, b): |
| 54 return float(a) / b if b else 0 |
| 55 |
| 56 |
| 53 class Describer(object): | 57 class Describer(object): |
| 54 def __init__(self, verbose=False, recursive=False): | 58 def __init__(self, verbose=False, recursive=False): |
| 55 self.verbose = verbose | 59 self.verbose = verbose |
| 56 self.recursive = recursive | 60 self.recursive = recursive |
| 57 | 61 |
| 58 def _DescribeSectionSizes(self, section_sizes): | 62 def _DescribeSectionSizes(self, section_sizes): |
| 59 relevant_names = models.SECTION_TO_SECTION_NAME.values() | 63 relevant_names = models.SECTION_TO_SECTION_NAME.values() |
| 60 section_names = sorted(k for k in section_sizes.iterkeys() | 64 section_names = sorted(k for k in section_sizes.iterkeys() |
| 61 if k in relevant_names or k.startswith('.data')) | 65 if k in relevant_names or k.startswith('.data')) |
| 62 total_bytes = sum(v for k, v in section_sizes.iteritems() | 66 total_bytes = sum(v for k, v in section_sizes.iteritems() |
| 63 if k in section_names and k != '.bss') | 67 if k in section_names and k != '.bss') |
| 64 yield '' | 68 yield '' |
| 65 yield 'Section Sizes (Total={} ({} bytes)):'.format( | 69 yield 'Section Sizes (Total={} ({} bytes)):'.format( |
| 66 _PrettySize(total_bytes), total_bytes) | 70 _PrettySize(total_bytes), total_bytes) |
| 67 for name in section_names: | 71 for name in section_names: |
| 68 size = section_sizes[name] | 72 size = section_sizes[name] |
| 69 if name == '.bss': | 73 if name == '.bss': |
| 70 yield ' {}: {} ({} bytes) (not included in totals)'.format( | 74 yield ' {}: {} ({} bytes) (not included in totals)'.format( |
| 71 name, _PrettySize(size), size) | 75 name, _PrettySize(size), size) |
| 72 else: | 76 else: |
| 73 percent = float(size) / total_bytes if total_bytes else 0 | 77 percent = _Divide(size, total_bytes) |
| 74 yield ' {}: {} ({} bytes) ({:.1%})'.format( | 78 yield ' {}: {} ({} bytes) ({:.1%})'.format( |
| 75 name, _PrettySize(size), size, percent) | 79 name, _PrettySize(size), size, percent) |
| 76 | 80 |
| 77 if self.verbose: | 81 if self.verbose: |
| 78 yield '' | 82 yield '' |
| 79 yield 'Other section sizes:' | 83 yield 'Other section sizes:' |
| 80 section_names = sorted(k for k in section_sizes.iterkeys() | 84 section_names = sorted(k for k in section_sizes.iterkeys() |
| 81 if k not in section_names) | 85 if k not in section_names) |
| 82 for name in section_names: | 86 for name in section_names: |
| 83 yield ' {}: {} ({} bytes)'.format( | 87 yield ' {}: {} ({} bytes)'.format( |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 119 running_percent = 0 | 123 running_percent = 0 |
| 120 is_diff = isinstance(group, models.SymbolDiff) | 124 is_diff = isinstance(group, models.SymbolDiff) |
| 121 all_groups = all(s.IsGroup() for s in group) | 125 all_groups = all(s.IsGroup() for s in group) |
| 122 | 126 |
| 123 indent_prefix = '> ' * indent | 127 indent_prefix = '> ' * indent |
| 124 diff_prefix = '' | 128 diff_prefix = '' |
| 125 total = group.pss | 129 total = group.pss |
| 126 for index, s in enumerate(group): | 130 for index, s in enumerate(group): |
| 127 if group.IsBss() or not s.IsBss(): | 131 if group.IsBss() or not s.IsBss(): |
| 128 running_total += s.pss | 132 running_total += s.pss |
| 129 running_percent = running_total / total | 133 running_percent = _Divide(running_total, total) |
| 130 for l in self._DescribeSymbol(s, single_line=all_groups): | 134 for l in self._DescribeSymbol(s, single_line=all_groups): |
| 131 if l[:4].isspace(): | 135 if l[:4].isspace(): |
| 132 indent_size = 8 + len(indent_prefix) + len(diff_prefix) | 136 indent_size = 8 + len(indent_prefix) + len(diff_prefix) |
| 133 yield '{} {}'.format(' ' * indent_size, l) | 137 yield '{} {}'.format(' ' * indent_size, l) |
| 134 else: | 138 else: |
| 135 if is_diff: | 139 if is_diff: |
| 136 diff_prefix = _DiffPrefix(group, s) | 140 diff_prefix = _DiffPrefix(group, s) |
| 137 yield '{}{}{:<4} {:>8} {:7} {}'.format( | 141 yield '{}{}{:<4} {:>8} {:7} {}'.format( |
| 138 indent_prefix, diff_prefix, str(index) + ')', | 142 indent_prefix, diff_prefix, str(index) + ')', |
| 139 _FormatPss(running_total), '({:.1%})'.format(running_percent), l) | 143 _FormatPss(running_total), '({:.1%})'.format(running_percent), l) |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 260 expected_size = sum(v for k, v in size_info.section_sizes.iteritems() | 264 expected_size = sum(v for k, v in size_info.section_sizes.iteritems() |
| 261 if k.startswith('.data')) | 265 if k.startswith('.data')) |
| 262 else: | 266 else: |
| 263 expected_size = size_info.section_sizes[ | 267 expected_size = size_info.section_sizes[ |
| 264 models.SECTION_TO_SECTION_NAME[section]] | 268 models.SECTION_TO_SECTION_NAME[section]] |
| 265 | 269 |
| 266 # Use raw_symbols in case symbols contains groups. | 270 # Use raw_symbols in case symbols contains groups. |
| 267 in_section = models.SymbolGroup(size_info.raw_symbols).WhereInSection( | 271 in_section = models.SymbolGroup(size_info.raw_symbols).WhereInSection( |
| 268 section) | 272 section) |
| 269 actual_size = in_section.size | 273 actual_size = in_section.size |
| 270 size_percent = float(actual_size) / expected_size | 274 size_percent = _Divide(actual_size, expected_size) |
| 271 yield ('Section {}: has {:.1%} of {} bytes accounted for from ' | 275 yield ('Section {}: has {:.1%} of {} bytes accounted for from ' |
| 272 '{} symbols. {} bytes are unaccounted for.').format( | 276 '{} symbols. {} bytes are unaccounted for.').format( |
| 273 section, size_percent, actual_size, len(in_section), | 277 section, size_percent, actual_size, len(in_section), |
| 274 expected_size - actual_size) | 278 expected_size - actual_size) |
| 275 star_syms = in_section.WhereNameMatches(r'^\*') | 279 star_syms = in_section.WhereNameMatches(r'^\*') |
| 276 padding = in_section.padding - star_syms.padding | 280 padding = in_section.padding - star_syms.padding |
| 277 anonymous_syms = star_syms.Inverted().WhereHasAnyAttribution().Inverted() | 281 anonymous_syms = star_syms.Inverted().WhereHasAnyAttribution().Inverted() |
| 278 yield '* Padding accounts for {} bytes ({:.1%})'.format( | 282 yield '* Padding accounts for {} bytes ({:.1%})'.format( |
| 279 padding, float(padding) / in_section.size) | 283 padding, _Divide(padding, in_section.size)) |
| 280 if len(star_syms): | 284 if len(star_syms): |
| 281 yield ('* {} placeholders (symbols that start with **) account for ' | 285 yield ('* {} placeholders (symbols that start with **) account for ' |
| 282 '{} bytes ({:.1%})').format( | 286 '{} bytes ({:.1%})').format( |
| 283 len(star_syms), star_syms.size, | 287 len(star_syms), star_syms.size, |
| 284 float(star_syms.size) / in_section.size) | 288 _Divide(star_syms.size, in_section.size)) |
| 285 if anonymous_syms: | 289 if anonymous_syms: |
| 286 yield '* {} anonymous symbols account for {} bytes ({:.1%})'.format( | 290 yield '* {} anonymous symbols account for {} bytes ({:.1%})'.format( |
| 287 len(anonymous_syms), int(anonymous_syms.pss), | 291 len(anonymous_syms), int(anonymous_syms.pss), |
| 288 float(star_syms.size) / in_section.size) | 292 _Divide(star_syms.size, in_section.size)) |
| 289 | 293 |
| 290 aliased_symbols = in_section.Filter(lambda s: s.aliases) | 294 aliased_symbols = in_section.Filter(lambda s: s.aliases) |
| 291 if section == 't': | 295 if section == 't': |
| 292 if len(aliased_symbols): | 296 if len(aliased_symbols): |
| 293 uniques = sum(1 for s in aliased_symbols.IterUniqueSymbols()) | 297 uniques = sum(1 for s in aliased_symbols.IterUniqueSymbols()) |
| 294 yield ('* Contains {} aliases, mapped to {} unique addresses ' | 298 yield ('* Contains {} aliases, mapped to {} unique addresses ' |
| 295 '({} bytes)').format( | 299 '({} bytes)').format( |
| 296 len(aliased_symbols), uniques, aliased_symbols.size) | 300 len(aliased_symbols), uniques, aliased_symbols.size) |
| 297 else: | 301 else: |
| 298 yield '* Contains 0 aliases' | 302 yield '* Contains 0 aliases' |
| (...skipping 29 matching lines...) Expand all Loading... |
| 328 | 332 |
| 329 def GenerateLines(obj, verbose=False, recursive=False): | 333 def GenerateLines(obj, verbose=False, recursive=False): |
| 330 """Returns an iterable of lines (without \n) that describes |obj|.""" | 334 """Returns an iterable of lines (without \n) that describes |obj|.""" |
| 331 return Describer(verbose=verbose, recursive=recursive).GenerateLines(obj) | 335 return Describer(verbose=verbose, recursive=recursive).GenerateLines(obj) |
| 332 | 336 |
| 333 | 337 |
| 334 def WriteLines(lines, func): | 338 def WriteLines(lines, func): |
| 335 for l in lines: | 339 for l in lines: |
| 336 func(l) | 340 func(l) |
| 337 func('\n') | 341 func('\n') |
| OLD | NEW |