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 |
| 245 aliased_symbols = in_section.Filter(lambda s: s.aliases) |
| 246 if len(aliased_symbols): |
| 247 uniques = sum(1 for s in aliased_symbols.IterUniqueSymbols()) |
| 248 yield '* Contains {} aliases, mapped to {} addresses ({} bytes)'.format( |
| 249 len(aliased_symbols), uniques, aliased_symbols.size) |
| 250 else: |
| 251 yield '* Contains 0 aliases' |
| 252 |
| 253 inlined_symbols = in_section.WhereObjectPathMatches('{shared}') |
| 254 if len(inlined_symbols): |
| 255 yield '* {} symbols have shared ownership ({} bytes)'.format( |
| 256 len(inlined_symbols), inlined_symbols.size) |
| 257 else: |
| 258 yield '* 0 symbols have shared ownership' |
245 | 259 |
246 star_syms = in_section.WhereNameMatches(r'^\*') | 260 star_syms = in_section.WhereNameMatches(r'^\*') |
247 attributed_syms = star_syms.Inverted().WhereHasAnyAttribution() | 261 attributed_syms = star_syms.Inverted().WhereHasAnyAttribution() |
248 anonymous_syms = attributed_syms.Inverted() | 262 anonymous_syms = attributed_syms.Inverted() |
249 if star_syms or anonymous_syms: | 263 if star_syms or anonymous_syms: |
250 missing_size = star_syms.size + anonymous_syms.size | 264 missing_size = star_syms.pss + anonymous_syms.pss |
251 yield ('+ Without %d merge sections and %d anonymous entries (' | 265 anon_str = '' |
252 'accounting for %d bytes):') % ( | 266 if len(anonymous_syms): |
253 len(star_syms), len(anonymous_syms), missing_size) | 267 anon_str = 'and {} anonymous entries '.format(len(anonymous_syms)) |
254 yield '+ ' + one_stat(attributed_syms) | 268 yield '* Without {} merge sections {}(accounting for {} bytes):'.format( |
| 269 len(star_syms), anon_str, int(missing_size)) |
| 270 yield ' * ' + one_stat(attributed_syms) |
255 | 271 |
256 | 272 |
257 def _UtcToLocal(utc): | 273 def _UtcToLocal(utc): |
258 epoch = time.mktime(utc.timetuple()) | 274 epoch = time.mktime(utc.timetuple()) |
259 offset = (datetime.datetime.fromtimestamp(epoch) - | 275 offset = (datetime.datetime.fromtimestamp(epoch) - |
260 datetime.datetime.utcfromtimestamp(epoch)) | 276 datetime.datetime.utcfromtimestamp(epoch)) |
261 return utc + offset | 277 return utc + offset |
262 | 278 |
263 | 279 |
264 def DescribeMetadata(metadata): | 280 def DescribeMetadata(metadata): |
265 display_dict = metadata.copy() | 281 display_dict = metadata.copy() |
266 timestamp = display_dict.get(models.METADATA_ELF_MTIME) | 282 timestamp = display_dict.get(models.METADATA_ELF_MTIME) |
267 if timestamp: | 283 if timestamp: |
268 timestamp_obj = datetime.datetime.utcfromtimestamp(timestamp) | 284 timestamp_obj = datetime.datetime.utcfromtimestamp(timestamp) |
269 display_dict[models.METADATA_ELF_MTIME] = ( | 285 display_dict[models.METADATA_ELF_MTIME] = ( |
270 _UtcToLocal(timestamp_obj).strftime('%Y-%m-%d %H:%M:%S')) | 286 _UtcToLocal(timestamp_obj).strftime('%Y-%m-%d %H:%M:%S')) |
271 gn_args = display_dict.get(models.METADATA_GN_ARGS) | 287 gn_args = display_dict.get(models.METADATA_GN_ARGS) |
272 if gn_args: | 288 if gn_args: |
273 display_dict[models.METADATA_GN_ARGS] = '; '.join(gn_args) | 289 display_dict[models.METADATA_GN_ARGS] = ' '.join(gn_args) |
274 return sorted('%s=%s' % t for t in display_dict.iteritems()) | 290 return sorted('%s=%s' % t for t in display_dict.iteritems()) |
275 | 291 |
276 | 292 |
277 def GenerateLines(obj, verbose=False, recursive=False): | 293 def GenerateLines(obj, verbose=False, recursive=False): |
278 """Returns an iterable of lines (without \n) that describes |obj|.""" | 294 """Returns an iterable of lines (without \n) that describes |obj|.""" |
279 return Describer(verbose=verbose, recursive=recursive).GenerateLines(obj) | 295 return Describer(verbose=verbose, recursive=recursive).GenerateLines(obj) |
280 | 296 |
281 | 297 |
282 def WriteLines(lines, func): | 298 def WriteLines(lines, func): |
283 for l in lines: | 299 for l in lines: |
284 func(l) | 300 func(l) |
285 func('\n') | 301 func('\n') |
OLD | NEW |