| 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 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 68 for name in section_names: | 68 for name in section_names: |
| 69 yield ' {}: {:,} bytes'.format(name, section_sizes[name]) | 69 yield ' {}: {:,} bytes'.format(name, section_sizes[name]) |
| 70 | 70 |
| 71 def _DescribeSymbol(self, sym): | 71 def _DescribeSymbol(self, sym): |
| 72 if sym.IsGroup(): | 72 if sym.IsGroup(): |
| 73 address = 'Group' | 73 address = 'Group' |
| 74 else: | 74 else: |
| 75 address = hex(sym.address) | 75 address = hex(sym.address) |
| 76 if self.verbose: | 76 if self.verbose: |
| 77 count_part = ' count=%d' % len(sym) if sym.IsGroup() else '' | 77 count_part = ' count=%d' % len(sym) if sym.IsGroup() else '' |
| 78 yield '{}@{:<9s} size={} padding={} size_without_padding={}{}'.format( | 78 yield '{}@{:<9s} pss={} padding={} size_without_padding={}{}'.format( |
| 79 sym.section, address, sym.size, sym.padding, sym.size_without_padding, | 79 sym.section, address, int(sym.pss), sym.padding, |
| 80 count_part) | 80 sym.size_without_padding, count_part) |
| 81 yield ' source_path={} \tobject_path={}'.format( | 81 yield ' source_path={} \tobject_path={}'.format( |
| 82 sym.source_path, sym.object_path) | 82 sym.source_path, sym.object_path) |
| 83 if sym.name: | 83 if sym.name: |
| 84 yield ' flags={} name={}'.format(sym.FlagsString(), sym.name) | 84 yield ' flags={} name={}'.format(sym.FlagsString(), sym.name) |
| 85 if sym.full_name: | 85 if sym.full_name: |
| 86 yield ' full_name={}'.format(sym.full_name) | 86 yield ' full_name={}'.format(sym.full_name) |
| 87 elif sym.full_name: | 87 elif sym.full_name: |
| 88 yield ' flags={} full_name={}'.format( | 88 yield ' flags={} full_name={}'.format( |
| 89 sym.FlagsString(), sym.full_name) | 89 sym.FlagsString(), sym.full_name) |
| 90 else: | 90 else: |
| 91 yield '{}@{:<9s} {:<7} {}'.format( | 91 yield '{}@{:<9s} {:<7} {}'.format( |
| 92 sym.section, address, sym.size, | 92 sym.section, address, int(sym.pss), |
| 93 sym.source_path or sym.object_path or '{no path}') | 93 sym.source_path or sym.object_path or '{no path}') |
| 94 if sym.name: | 94 if sym.name: |
| 95 count_part = ' (count=%d)' % len(sym) if sym.IsGroup() else '' | 95 count_part = ' (count=%d)' % len(sym) if sym.IsGroup() else '' |
| 96 yield ' {}{}'.format(sym.name, count_part) | 96 yield ' {}{}'.format(sym.name, count_part) |
| 97 | 97 |
| 98 def _DescribeSymbolGroupChildren(self, group, indent=0): | 98 def _DescribeSymbolGroupChildren(self, group, indent=0): |
| 99 running_total = 0 | 99 running_total = 0 |
| 100 sorted_syms = group if group.is_sorted else group.Sorted() | 100 sorted_syms = group if group.is_sorted else group.Sorted() |
| 101 is_diff = isinstance(group, models.SymbolDiff) | 101 is_diff = isinstance(group, models.SymbolDiff) |
| 102 | 102 |
| 103 indent_prefix = '> ' * indent | 103 indent_prefix = '> ' * indent |
| 104 diff_prefix = '' | 104 diff_prefix = '' |
| 105 for s in sorted_syms: | 105 for s in sorted_syms: |
| 106 if group.IsBss() or not s.IsBss(): | 106 if group.IsBss() or not s.IsBss(): |
| 107 running_total += s.size | 107 running_total += s.pss |
| 108 for l in self._DescribeSymbol(s): | 108 for l in self._DescribeSymbol(s): |
| 109 if l[:4].isspace(): | 109 if l[:4].isspace(): |
| 110 indent_size = 8 + len(indent_prefix) + len(diff_prefix) | 110 indent_size = 8 + len(indent_prefix) + len(diff_prefix) |
| 111 yield '{} {}'.format(' ' * indent_size, l) | 111 yield '{} {}'.format(' ' * indent_size, l) |
| 112 else: | 112 else: |
| 113 if is_diff: | 113 if is_diff: |
| 114 diff_prefix = _DiffPrefix(group, s) | 114 diff_prefix = _DiffPrefix(group, s) |
| 115 yield '{}{}{:8} {}'.format(indent_prefix, diff_prefix, | 115 yield '{}{}{:8} {}'.format(indent_prefix, diff_prefix, |
| 116 running_total, l) | 116 int(running_total), l) |
| 117 | 117 |
| 118 if self.recursive and s.IsGroup(): | 118 if self.recursive and s.IsGroup(): |
| 119 for l in self._DescribeSymbolGroupChildren(s, indent=indent + 1): | 119 for l in self._DescribeSymbolGroupChildren(s, indent=indent + 1): |
| 120 yield l | 120 yield l |
| 121 | 121 |
| 122 def _DescribeSymbolGroup(self, group): | 122 def _DescribeSymbolGroup(self, group): |
| 123 total_size = group.size | 123 total_size = group.pss |
| 124 code_syms = group.WhereInSection('t') | 124 code_syms = group.WhereInSection('t') |
| 125 code_size = code_syms.size | 125 code_size = code_syms.pss |
| 126 ro_size = code_syms.Inverted().WhereInSection('r').size | 126 ro_size = code_syms.Inverted().WhereInSection('r').pss |
| 127 unique_paths = set(s.object_path for s in group) | 127 unique_paths = set(s.object_path for s in group) |
| 128 header_desc = [ | 128 header_desc = [ |
| 129 'Showing {:,} symbols with total size: {} bytes'.format( | 129 'Showing {:,} symbols with total pss: {} bytes'.format( |
| 130 len(group), total_size), | 130 len(group), int(total_size)), |
| 131 '.text={:<10} .rodata={:<10} other={:<10} total={}'.format( | 131 '.text={:<10} .rodata={:<10} other={:<10} total={}'.format( |
| 132 _PrettySize(code_size), _PrettySize(ro_size), | 132 _PrettySize(int(code_size)), _PrettySize(int(ro_size)), |
| 133 _PrettySize(total_size - code_size - ro_size), | 133 _PrettySize(int(total_size - code_size - ro_size)), |
| 134 _PrettySize(total_size)), | 134 _PrettySize(int(total_size))), |
| 135 'Number of object files: {}'.format(len(unique_paths)), | 135 'Number of object files: {}'.format(len(unique_paths)), |
| 136 '', | 136 '', |
| 137 'First columns are: running total, type, size', | 137 'First columns are: running total, address, pss', |
| 138 ] | 138 ] |
| 139 children_desc = self._DescribeSymbolGroupChildren(group) | 139 children_desc = self._DescribeSymbolGroupChildren(group) |
| 140 return itertools.chain(header_desc, children_desc) | 140 return itertools.chain(header_desc, children_desc) |
| 141 | 141 |
| 142 def _DescribeSymbolDiff(self, diff): | 142 def _DescribeSymbolDiff(self, diff): |
| 143 header_template = ('{} symbols added (+), {} changed (~), {} removed (-), ' | 143 header_template = ('{} symbols added (+), {} changed (~), {} removed (-), ' |
| 144 '{} unchanged ({})') | 144 '{} unchanged ({})') |
| 145 unchanged_msg = '=' if self.verbose else 'not shown' | 145 unchanged_msg = '=' if self.verbose else 'not shown' |
| 146 symbol_delta_desc = [header_template.format( | 146 symbol_delta_desc = [header_template.format( |
| 147 diff.added_count, diff.changed_count, diff.removed_count, | 147 diff.added_count, diff.changed_count, diff.removed_count, |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 223 symbols = models.SymbolGroup(size_info.raw_symbols) | 223 symbols = models.SymbolGroup(size_info.raw_symbols) |
| 224 for section in models.SECTION_TO_SECTION_NAME: | 224 for section in models.SECTION_TO_SECTION_NAME: |
| 225 if section == 'd': | 225 if section == 'd': |
| 226 expected_size = sum(v for k, v in size_info.section_sizes.iteritems() | 226 expected_size = sum(v for k, v in size_info.section_sizes.iteritems() |
| 227 if k.startswith('.data')) | 227 if k.startswith('.data')) |
| 228 else: | 228 else: |
| 229 expected_size = size_info.section_sizes[ | 229 expected_size = size_info.section_sizes[ |
| 230 models.SECTION_TO_SECTION_NAME[section]] | 230 models.SECTION_TO_SECTION_NAME[section]] |
| 231 | 231 |
| 232 def one_stat(group): | 232 def one_stat(group): |
| 233 template = ('Section %s has %.1f%% of %d bytes accounted for from ' | 233 template = ('Section {}: has {:.1%} of {} bytes accounted for from ' |
| 234 '%d symbols. %d bytes are unaccounted for. Padding ' | 234 '{} symbols. {} bytes are unaccounted for.') |
| 235 'accounts for %d bytes') | |
| 236 actual_size = group.size | 235 actual_size = group.size |
| 237 count = len(group) | 236 size_percent = float(actual_size) / expected_size |
| 238 padding = group.padding | 237 return template.format(section, size_percent, actual_size, len(group), |
| 239 size_percent = 100.0 * actual_size / expected_size | 238 expected_size - actual_size) |
| 240 return (template % (section, size_percent, actual_size, count, | |
| 241 expected_size - actual_size, padding)) | |
| 242 | 239 |
| 243 in_section = symbols.WhereInSection(section) | 240 in_section = symbols.WhereInSection(section) |
| 244 yield one_stat(in_section) | 241 yield one_stat(in_section) |
| 242 yield '* Padding accounts for {} bytes ({:.1%})'.format( |
| 243 in_section.padding, float(in_section.padding) / in_section.size) |
| 244 aliased_symbols = in_section.Filter(lambda s: s.aliases) |
| 245 if len(aliased_symbols): |
| 246 uniques = sum(1 for s in aliased_symbols.IterUniqueSymbols()) |
| 247 yield '* Contains {} aliases, mapped to {} addresses ({} bytes)'.format( |
| 248 len(aliased_symbols), uniques, aliased_symbols.size) |
| 249 inlined_symbols = in_section.WhereObjectPathMatches('{shared}') |
| 250 if len(inlined_symbols): |
| 251 yield '* {} symbols have shared ownership ({} bytes)'.format( |
| 252 len(inlined_symbols), inlined_symbols.size) |
| 245 | 253 |
| 246 star_syms = in_section.WhereNameMatches(r'^\*') | 254 star_syms = in_section.WhereNameMatches(r'^\*') |
| 247 attributed_syms = star_syms.Inverted().WhereHasAnyAttribution() | 255 attributed_syms = star_syms.Inverted().WhereHasAnyAttribution() |
| 248 anonymous_syms = attributed_syms.Inverted() | 256 anonymous_syms = attributed_syms.Inverted() |
| 249 if star_syms or anonymous_syms: | 257 if star_syms or anonymous_syms: |
| 250 missing_size = star_syms.size + anonymous_syms.size | 258 missing_size = star_syms.pss + anonymous_syms.pss |
| 251 yield ('+ Without %d merge sections and %d anonymous entries (' | 259 anon_str = '' |
| 252 'accounting for %d bytes):') % ( | 260 if len(anonymous_syms): |
| 253 len(star_syms), len(anonymous_syms), missing_size) | 261 anon_str = 'and {} anonymous entries '.format(len(anonymous_syms)) |
| 254 yield '+ ' + one_stat(attributed_syms) | 262 yield '* Without {} merge sections {}(accounting for {} bytes):'.format( |
| 263 len(star_syms), anon_str, int(missing_size)) |
| 264 yield ' * ' + one_stat(attributed_syms) |
| 255 | 265 |
| 256 | 266 |
| 257 def _UtcToLocal(utc): | 267 def _UtcToLocal(utc): |
| 258 epoch = time.mktime(utc.timetuple()) | 268 epoch = time.mktime(utc.timetuple()) |
| 259 offset = (datetime.datetime.fromtimestamp(epoch) - | 269 offset = (datetime.datetime.fromtimestamp(epoch) - |
| 260 datetime.datetime.utcfromtimestamp(epoch)) | 270 datetime.datetime.utcfromtimestamp(epoch)) |
| 261 return utc + offset | 271 return utc + offset |
| 262 | 272 |
| 263 | 273 |
| 264 def DescribeMetadata(metadata): | 274 def DescribeMetadata(metadata): |
| 265 display_dict = metadata.copy() | 275 display_dict = metadata.copy() |
| 266 timestamp = display_dict.get(models.METADATA_ELF_MTIME) | 276 timestamp = display_dict.get(models.METADATA_ELF_MTIME) |
| 267 if timestamp: | 277 if timestamp: |
| 268 timestamp_obj = datetime.datetime.utcfromtimestamp(timestamp) | 278 timestamp_obj = datetime.datetime.utcfromtimestamp(timestamp) |
| 269 display_dict[models.METADATA_ELF_MTIME] = ( | 279 display_dict[models.METADATA_ELF_MTIME] = ( |
| 270 _UtcToLocal(timestamp_obj).strftime('%Y-%m-%d %H:%M:%S')) | 280 _UtcToLocal(timestamp_obj).strftime('%Y-%m-%d %H:%M:%S')) |
| 271 gn_args = display_dict.get(models.METADATA_GN_ARGS) | 281 gn_args = display_dict.get(models.METADATA_GN_ARGS) |
| 272 if gn_args: | 282 if gn_args: |
| 273 display_dict[models.METADATA_GN_ARGS] = '; '.join(gn_args) | 283 display_dict[models.METADATA_GN_ARGS] = ' '.join(gn_args) |
| 274 return sorted('%s=%s' % t for t in display_dict.iteritems()) | 284 return sorted('%s=%s' % t for t in display_dict.iteritems()) |
| 275 | 285 |
| 276 | 286 |
| 277 def GenerateLines(obj, verbose=False, recursive=False): | 287 def GenerateLines(obj, verbose=False, recursive=False): |
| 278 """Returns an iterable of lines (without \n) that describes |obj|.""" | 288 """Returns an iterable of lines (without \n) that describes |obj|.""" |
| 279 return Describer(verbose=verbose, recursive=recursive).GenerateLines(obj) | 289 return Describer(verbose=verbose, recursive=recursive).GenerateLines(obj) |
| 280 | 290 |
| 281 | 291 |
| 282 def WriteLines(lines, func): | 292 def WriteLines(lines, func): |
| 283 for l in lines: | 293 for l in lines: |
| 284 func(l) | 294 func(l) |
| 285 func('\n') | 295 func('\n') |
| OLD | NEW |