Chromium Code Reviews| 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 |
| 11 | 11 |
| 12 | 12 |
| 13 _DIFF_PREFIX_BY_STATUS = ['= ', '~ ', '+ ', '- '] | |
| 14 | |
| 15 | |
| 16 def _PrettySize(size): | 13 def _PrettySize(size): |
| 17 # Arbitrarily chosen cut-off. | 14 # Arbitrarily chosen cut-off. |
| 18 if abs(size) < 2000: | 15 if abs(size) < 2000: |
| 19 return '%d bytes' % size | 16 return '%d bytes' % size |
| 20 # Always show 3 digits. | 17 # Always show 3 digits. |
| 21 size /= 1024.0 | 18 size /= 1024.0 |
| 22 if abs(size) < 10: | 19 if abs(size) < 10: |
| 23 return '%.2fkb' % size | 20 return '%.2fkb' % size |
| 24 elif abs(size) < 100: | 21 elif abs(size) < 100: |
| 25 return '%.1fkb' % size | 22 return '%.1fkb' % size |
| 26 elif abs(size) < 1024: | 23 elif abs(size) < 1024: |
| 27 return '%dkb' % size | 24 return '%dkb' % size |
| 28 size /= 1024.0 | 25 size /= 1024.0 |
| 29 if abs(size) < 10: | 26 if abs(size) < 10: |
| 30 return '%.2fmb' % size | 27 return '%.2fmb' % size |
| 31 # We shouldn't be seeing sizes > 100mb. | 28 # We shouldn't be seeing sizes > 100mb. |
| 32 return '%.1fmb' % size | 29 return '%.1fmb' % size |
| 33 | 30 |
| 34 | 31 |
| 35 def _FormatPss(pss): | 32 def _FormatPss(pss): |
| 36 # Shows a decimal for small numbers to make it clear that a shared symbol has | 33 # Shows a decimal for small numbers to make it clear that a shared symbol has |
| 37 # a non-zero pss. | 34 # a non-zero pss. |
| 38 if pss > 10: | 35 if abs(pss) > 10: |
| 39 return str(int(pss)) | 36 return str(int(pss)) |
| 40 ret = str(round(pss, 1)) | 37 ret = str(round(pss, 1)) |
| 41 if ret.endswith('.0'): | 38 if ret.endswith('.0'): |
| 42 ret = ret[:-2] | 39 ret = ret[:-2] |
| 43 if ret == '0' and pss: | 40 if ret == '0' and pss: |
| 44 ret = '~0' | 41 ret = '~0' |
| 45 return ret | 42 return ret |
| 46 | 43 |
| 47 | 44 |
| 48 def _Divide(a, b): | 45 def _Divide(a, b): |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 98 not_included_part = ' (not included in totals)' | 95 not_included_part = ' (not included in totals)' |
| 99 yield ' {}: {} ({} bytes){}'.format( | 96 yield ' {}: {} ({} bytes){}'.format( |
| 100 name, _PrettySize(section_sizes[name]), section_sizes[name], | 97 name, _PrettySize(section_sizes[name]), section_sizes[name], |
| 101 not_included_part) | 98 not_included_part) |
| 102 | 99 |
| 103 def _DescribeSymbol(self, sym, single_line=False): | 100 def _DescribeSymbol(self, sym, single_line=False): |
| 104 if sym.IsGroup(): | 101 if sym.IsGroup(): |
| 105 address = 'Group' | 102 address = 'Group' |
| 106 else: | 103 else: |
| 107 address = hex(sym.address) | 104 address = hex(sym.address) |
| 105 last_field = '' | |
| 106 if sym.IsGroup(): | |
| 107 last_field = 'count=%d' % len(sym) | |
| 108 elif sym.IsDelta(): | |
| 109 if sym.before_symbol is None: | |
| 110 num_aliases = sym.after_symbol.num_aliases | |
| 111 elif sym.after_symbol is None: | |
| 112 num_aliases = sym.before_symbol.num_aliases | |
| 113 elif sym.before_symbol.num_aliases == sym.after_symbol.num_aliases: | |
| 114 num_aliases = sym.before_symbol.num_aliases | |
| 115 else: | |
| 116 last_field = 'num_aliases=%d->%d' % ( | |
| 117 sym.before_symbol.num_aliases, sym.after_symbol.num_aliases) | |
| 118 if not last_field and (num_aliases > 1 or self.verbose): | |
| 119 last_field = 'num_aliases=%d' % num_aliases | |
| 120 elif sym.num_aliases > 1 or self.verbose: | |
| 121 last_field = 'num_aliases=%d' % sym.num_aliases | |
| 122 | |
| 123 if sym.IsDelta(): | |
| 124 if sym.IsGroup(): | |
| 125 b = sum(s.before_symbol.size_without_padding if s.before_symbol else 0 | |
| 126 for s in sym) | |
| 127 a = sum(s.after_symbol.size_without_padding if s.after_symbol else 0 | |
| 128 for s in sym) | |
| 129 else: | |
| 130 b = sym.before_symbol.size_without_padding if sym.before_symbol else 0 | |
| 131 a = sym.after_symbol.size_without_padding if sym.after_symbol else 0 | |
| 132 pss_with_sign = _FormatPss(sym.pss) | |
| 133 if pss_with_sign[0] not in '~-': | |
|
estevenson
2017/06/15 16:10:45
nit: does it make sense for _FormatPss() to always
agrieve
2017/06/15 19:57:04
The idea is to only include the explicit + when sh
| |
| 134 pss_with_sign = '+' + pss_with_sign | |
| 135 pss_field = '{} ({}->{})'.format(pss_with_sign, b, a) | |
| 136 elif sym.num_aliases > 1: | |
| 137 pss_field = '{} (size={})'.format(_FormatPss(sym.pss), sym.size) | |
| 138 else: | |
| 139 pss_field = '{}'.format(_FormatPss(sym.pss)) | |
| 140 | |
| 108 if self.verbose: | 141 if self.verbose: |
| 109 count_part = ' count=%d' % len(sym) if sym.IsGroup() else '' | 142 if last_field: |
| 110 yield '{}@{:<9s} pss={} padding={} size_without_padding={}{}'.format( | 143 last_field = ' ' + last_field |
| 111 sym.section, address, _FormatPss(sym.pss), sym.padding, | 144 if sym.IsDelta(): |
| 112 sym.size_without_padding, count_part) | 145 yield '{}@{:<9s} {}{}'.format( |
| 146 sym.section, address, pss_field, last_field) | |
| 147 else: | |
| 148 l = '{}@{:<9s} pss={} padding={}{}'.format( | |
| 149 sym.section, address, pss_field, sym.padding, last_field) | |
| 150 yield l | |
| 113 yield ' source_path={} \tobject_path={}'.format( | 151 yield ' source_path={} \tobject_path={}'.format( |
| 114 sym.source_path, sym.object_path) | 152 sym.source_path, sym.object_path) |
| 115 if sym.name: | 153 if sym.name: |
| 116 yield ' flags={} name={}'.format(sym.FlagsString(), sym.name) | 154 yield ' flags={} name={}'.format(sym.FlagsString(), sym.name) |
| 117 if sym.full_name is not sym.name: | 155 if sym.full_name is not sym.name: |
| 118 yield ' full_name={}'.format(sym.full_name) | 156 yield ' full_name={}'.format(sym.full_name) |
| 119 elif sym.full_name: | 157 elif sym.full_name: |
| 120 yield ' flags={} full_name={}'.format( | 158 yield ' flags={} full_name={}'.format( |
| 121 sym.FlagsString(), sym.full_name) | 159 sym.FlagsString(), sym.full_name) |
| 122 elif single_line: | |
| 123 count_part = ' (count=%d)' % len(sym) if sym.IsGroup() else '' | |
| 124 yield '{}@{:<9s} {:<7} {}{}'.format( | |
| 125 sym.section, address, _FormatPss(sym.pss), sym.name, count_part) | |
| 126 else: | 160 else: |
| 127 yield '{}@{:<9s} {:<7} {}'.format( | 161 if last_field: |
| 128 sym.section, address, _FormatPss(sym.pss), | 162 last_field = ' ({})'.format(last_field) |
| 129 sym.source_path or sym.object_path or '{no path}') | 163 if sym.IsDelta(): |
| 130 if sym.name: | 164 pss_field = '{:<18}'.format(pss_field) |
| 131 count_part = ' (count=%d)' % len(sym) if sym.IsGroup() else '' | 165 else: |
| 132 yield ' {}{}'.format(sym.name, count_part) | 166 pss_field = '{:<14}'.format(pss_field) |
| 167 if single_line: | |
| 168 yield '{}@{:<9s} {} {}{}'.format( | |
| 169 sym.section, address, pss_field, sym.name, last_field) | |
| 170 else: | |
| 171 yield '{}@{:<9s} {} {}'.format( | |
| 172 sym.section, address, pss_field, | |
| 173 sym.source_path or sym.object_path or '{no path}') | |
| 174 if sym.name: | |
| 175 yield ' {}{}'.format(sym.name, last_field) | |
| 133 | 176 |
| 134 def _DescribeSymbolGroupChildren(self, group, indent=0): | 177 def _DescribeSymbolGroupChildren(self, group, indent=0): |
| 135 running_total = 0 | 178 running_total = 0 |
| 136 running_percent = 0 | 179 running_percent = 0 |
| 137 is_diff = isinstance(group, models.SymbolDiff) | 180 is_delta = group.IsDelta() |
| 138 all_groups = all(s.IsGroup() for s in group) | 181 all_groups = all(s.IsGroup() for s in group) |
| 139 | 182 |
| 140 indent_prefix = '> ' * indent | 183 indent_prefix = '> ' * indent |
| 141 diff_prefix = '' | 184 diff_prefix = '' |
| 142 total = group.pss | 185 total = group.pss |
| 143 for index, s in enumerate(group): | 186 for index, s in enumerate(group): |
| 144 if group.IsBss() or not s.IsBss(): | 187 if group.IsBss() or not s.IsBss(): |
| 145 running_total += s.pss | 188 running_total += s.pss |
| 146 running_percent = _Divide(running_total, total) | 189 running_percent = _Divide(running_total, total) |
| 147 for l in self._DescribeSymbol(s, single_line=all_groups): | 190 for l in self._DescribeSymbol(s, single_line=all_groups): |
| 148 if l[:4].isspace(): | 191 if l[:4].isspace(): |
| 149 indent_size = 8 + len(indent_prefix) + len(diff_prefix) | 192 indent_size = 8 + len(indent_prefix) + len(diff_prefix) |
| 150 yield '{} {}'.format(' ' * indent_size, l) | 193 yield '{} {}'.format(' ' * indent_size, l) |
| 151 else: | 194 else: |
| 152 if is_diff: | 195 if is_delta: |
| 153 diff_prefix = _DIFF_PREFIX_BY_STATUS[group.DiffStatus(s)] | 196 diff_prefix = models.DIFF_PREFIX_BY_STATUS[s.diff_status] |
| 154 yield '{}{}{:<4} {:>8} {:7} {}'.format( | 197 yield '{}{}{:<4} {:>8} {:7} {}'.format( |
| 155 indent_prefix, diff_prefix, str(index) + ')', | 198 indent_prefix, diff_prefix, str(index) + ')', |
| 156 _FormatPss(running_total), '({:.1%})'.format(running_percent), l) | 199 _FormatPss(running_total), '({:.1%})'.format(running_percent), l) |
| 157 | 200 |
| 158 if self.recursive and s.IsGroup(): | 201 if self.recursive and s.IsGroup(): |
| 159 for l in self._DescribeSymbolGroupChildren(s, indent=indent + 1): | 202 for l in self._DescribeSymbolGroupChildren(s, indent=indent + 1): |
| 160 yield l | 203 yield l |
| 161 | 204 |
| 162 def _DescribeSymbolGroup(self, group): | 205 def _DescribeSymbolGroup(self, group): |
| 163 total_size = group.pss | 206 total_size = group.pss |
| 164 code_size = 0 | 207 code_size = 0 |
| 165 ro_size = 0 | 208 ro_size = 0 |
| 166 data_size = 0 | 209 data_size = 0 |
| 167 bss_size = 0 | 210 bss_size = 0 |
| 168 unique_paths = set() | 211 unique_paths = set() |
| 169 for s in group.IterLeafSymbols(): | 212 for s in group.IterLeafSymbols(): |
| 170 if s.section == 't': | 213 if s.section == 't': |
| 171 code_size += s.pss | 214 code_size += s.pss |
| 172 elif s.section == 'r': | 215 elif s.section == 'r': |
| 173 ro_size += s.pss | 216 ro_size += s.pss |
| 174 elif s.section == 'd': | 217 elif s.section == 'd': |
| 175 data_size += s.pss | 218 data_size += s.pss |
| 176 elif s.section == 'b': | 219 elif s.section == 'b': |
| 177 bss_size += s.pss | 220 bss_size += s.pss |
| 178 # Ignore paths like foo/{shared}/2 | 221 # Ignore paths like foo/{shared}/2 |
| 179 if '{' not in s.object_path: | 222 if '{' not in s.object_path: |
| 180 unique_paths.add(s.object_path) | 223 unique_paths.add(s.object_path) |
| 224 | |
| 225 if group.IsDelta(): | |
| 226 unique_part = 'aliases not grouped for diffs' | |
| 227 else: | |
| 228 unique_part = '{:,} unique'.format(group.CountUniqueSymbols()) | |
| 229 | |
| 230 if self.verbose: | |
| 231 titles = 'Index | Running Total | Section@Address | ...' | |
| 232 elif group.IsDelta(): | |
| 233 titles = (u'Index | Running Total | Section@Address | \u0394 PSS ' | |
| 234 u'(\u0394 size_without_padding) | Path').encode('utf-8') | |
| 235 else: | |
| 236 titles = ('Index | Running Total | Section@Address | PSS | Path') | |
| 237 | |
| 181 header_desc = [ | 238 header_desc = [ |
| 182 'Showing {:,} symbols ({:,} unique) with total pss: {} bytes'.format( | 239 'Showing {:,} symbols ({}) with total pss: {} bytes'.format( |
| 183 len(group), group.CountUniqueSymbols(), int(total_size)), | 240 len(group), unique_part, int(total_size)), |
| 184 '.text={:<10} .rodata={:<10} .data*={:<10} .bss={:<10} total={}'.format( | 241 '.text={:<10} .rodata={:<10} .data*={:<10} .bss={:<10} total={}'.format( |
| 185 _PrettySize(int(code_size)), _PrettySize(int(ro_size)), | 242 _PrettySize(int(code_size)), _PrettySize(int(ro_size)), |
| 186 _PrettySize(int(data_size)), _PrettySize(int(bss_size)), | 243 _PrettySize(int(data_size)), _PrettySize(int(bss_size)), |
| 187 _PrettySize(int(total_size))), | 244 _PrettySize(int(total_size))), |
| 188 'Number of unique paths: {}'.format(len(unique_paths)), | 245 'Number of unique paths: {}'.format(len(unique_paths)), |
| 189 '', | 246 '', |
| 190 'Index, Running Total, Section@Address, PSS', | 247 titles, |
| 191 '-' * 60 | 248 '-' * 60 |
| 192 ] | 249 ] |
| 250 # Apply this filter after calcualating stats since an alias being removed | |
| 251 # causes a some symbols to be UNCHANGED, yet have pss != 0. | |
|
estevenson
2017/06/15 16:10:45
nit: remove 'a'
agrieve
2017/06/15 19:57:04
Done.
| |
| 252 if group.IsDelta() and not self.verbose: | |
| 253 group = group.WhereDiffStatusIs(models.DIFF_STATUS_UNCHANGED).Inverted() | |
| 193 children_desc = self._DescribeSymbolGroupChildren(group) | 254 children_desc = self._DescribeSymbolGroupChildren(group) |
| 194 return itertools.chain(header_desc, children_desc) | 255 return itertools.chain(header_desc, children_desc) |
| 195 | 256 |
| 196 def _DescribeDiffObjectPaths(self, diff): | 257 def _DescribeDiffObjectPaths(self, delta_group): |
| 197 paths_by_status = [set(), set(), set(), set()] | 258 paths_by_status = [set(), set(), set(), set()] |
| 198 def helper(group): | 259 for s in delta_group.IterLeafSymbols(): |
| 199 for s in group: | 260 path = s.source_path or s.object_path |
| 200 if s.IsGroup(): | 261 # Ignore paths like foo/{shared}/2 |
| 201 helper(s) | 262 if '{' not in path: |
| 202 else: | 263 paths_by_status[s.diff_status].add(path) |
| 203 path = s.source_path or s.object_path | |
| 204 # Ignore paths like foo/{shared}/2 | |
| 205 if '{' not in path: | |
| 206 paths_by_status[group.DiffStatus(s)].add(path) | |
| 207 helper(diff) | |
| 208 # Initial paths sets are those where *any* symbol is | 264 # Initial paths sets are those where *any* symbol is |
| 209 # unchanged/changed/added/removed. | 265 # unchanged/changed/added/removed. |
| 210 unchanged, changed, added, removed = paths_by_status | 266 unchanged, changed, added, removed = paths_by_status |
| 211 # Consider a path with both adds & removes as "changed". | 267 # Consider a path with both adds & removes as "changed". |
| 212 changed.update(added.intersection(removed)) | 268 changed.update(added.intersection(removed)) |
| 213 # Consider a path added / removed only when all symbols are new/removed. | 269 # Consider a path added / removed only when all symbols are new/removed. |
| 214 added.difference_update(unchanged) | 270 added.difference_update(unchanged) |
| 215 added.difference_update(changed) | 271 added.difference_update(changed) |
| 216 added.difference_update(removed) | 272 added.difference_update(removed) |
| 217 removed.difference_update(unchanged) | 273 removed.difference_update(unchanged) |
| 218 removed.difference_update(changed) | 274 removed.difference_update(changed) |
| 219 removed.difference_update(added) | 275 removed.difference_update(added) |
| 220 yield '{} paths added, {} removed, {} changed'.format( | 276 yield '{} paths added, {} removed, {} changed'.format( |
| 221 len(added), len(removed), len(changed)) | 277 len(added), len(removed), len(changed)) |
| 222 | 278 |
| 223 if self.verbose and len(added): | 279 if self.verbose and len(added): |
| 224 yield 'Added files:' | 280 yield 'Added files:' |
| 225 for p in sorted(added): | 281 for p in sorted(added): |
| 226 yield ' ' + p | 282 yield ' ' + p |
| 227 if self.verbose and len(removed): | 283 if self.verbose and len(removed): |
| 228 yield 'Removed files:' | 284 yield 'Removed files:' |
| 229 for p in sorted(removed): | 285 for p in sorted(removed): |
| 230 yield ' ' + p | 286 yield ' ' + p |
| 231 if self.verbose and len(changed): | 287 if self.verbose and len(changed): |
| 232 yield 'Changed files:' | 288 yield 'Changed files:' |
| 233 for p in sorted(changed): | 289 for p in sorted(changed): |
| 234 yield ' ' + p | 290 yield ' ' + p |
| 235 | 291 |
| 236 def _DescribeSymbolDiff(self, diff): | 292 def _DescribeDeltaSymbolGroup(self, delta_group): |
| 237 header_template = ('{} symbols added (+), {} changed (~), {} removed (-), ' | 293 header_template = ('{} symbols added (+), {} changed (~), {} removed (-), ' |
| 238 '{} unchanged ({})') | 294 '{} unchanged ({})') |
| 239 unchanged_msg = '=' if self.verbose else 'not shown' | 295 unchanged_msg = '=' if self.verbose else 'not shown' |
| 240 symbol_delta_desc = [header_template.format( | 296 counts = delta_group.CountsByDiffStatus() |
| 241 diff.added_count, diff.changed_count, diff.removed_count, | 297 unqiue_counts = delta_group.CountUniqueSymbols() |
|
estevenson
2017/06/15 16:10:45
nit: spelling. Might be a little more readable to
agrieve
2017/06/15 19:57:04
Done.
| |
| 242 diff.unchanged_count, unchanged_msg)] | 298 diff_summary_desc = [ |
| 243 path_delta_desc = self._DescribeDiffObjectPaths(diff) | 299 header_template.format( |
| 300 counts[models.DIFF_STATUS_ADDED], | |
| 301 counts[models.DIFF_STATUS_CHANGED], | |
| 302 counts[models.DIFF_STATUS_REMOVED], | |
| 303 counts[models.DIFF_STATUS_UNCHANGED], | |
| 304 unchanged_msg), | |
| 305 'Number of unique symbols {} -> {} ({:+})'.format( | |
| 306 unqiue_counts[0], unqiue_counts[1], | |
| 307 unqiue_counts[1] - unqiue_counts[0]), | |
| 308 ] | |
| 309 path_delta_desc = self._DescribeDiffObjectPaths(delta_group) | |
| 244 | 310 |
| 245 diff = diff if self.verbose else diff.WhereNotUnchanged() | 311 group_desc = self._DescribeSymbolGroup(delta_group) |
| 246 group_desc = self._DescribeSymbolGroup(diff) | 312 return itertools.chain(diff_summary_desc, path_delta_desc, ('',), |
| 247 return itertools.chain(symbol_delta_desc, path_delta_desc, ('',), | |
| 248 group_desc) | 313 group_desc) |
| 249 | 314 |
| 250 def _DescribeSizeInfoDiff(self, diff): | 315 def _DescribeDeltaSizeInfo(self, diff): |
| 251 common_metadata = {k: v for k, v in diff.before_metadata.iteritems() | 316 common_metadata = {k: v for k, v in diff.before_metadata.iteritems() |
| 252 if diff.after_metadata[k] == v} | 317 if diff.after_metadata[k] == v} |
| 253 before_metadata = {k: v for k, v in diff.before_metadata.iteritems() | 318 before_metadata = {k: v for k, v in diff.before_metadata.iteritems() |
| 254 if k not in common_metadata} | 319 if k not in common_metadata} |
| 255 after_metadata = {k: v for k, v in diff.after_metadata.iteritems() | 320 after_metadata = {k: v for k, v in diff.after_metadata.iteritems() |
| 256 if k not in common_metadata} | 321 if k not in common_metadata} |
| 257 metadata_desc = itertools.chain( | 322 metadata_desc = itertools.chain( |
| 258 ('Common Metadata:',), | 323 ('Common Metadata:',), |
| 259 (' %s' % line for line in DescribeMetadata(common_metadata)), | 324 (' %s' % line for line in DescribeMetadata(common_metadata)), |
| 260 ('Old Metadata:',), | 325 ('Old Metadata:',), |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 272 section_desc = self._DescribeSectionSizes(size_info.section_sizes) | 337 section_desc = self._DescribeSectionSizes(size_info.section_sizes) |
| 273 coverage_desc = () | 338 coverage_desc = () |
| 274 if self.verbose: | 339 if self.verbose: |
| 275 coverage_desc = itertools.chain( | 340 coverage_desc = itertools.chain( |
| 276 ('',), DescribeSizeInfoCoverage(size_info)) | 341 ('',), DescribeSizeInfoCoverage(size_info)) |
| 277 group_desc = self.GenerateLines(size_info.symbols) | 342 group_desc = self.GenerateLines(size_info.symbols) |
| 278 return itertools.chain(metadata_desc, section_desc, coverage_desc, ('',), | 343 return itertools.chain(metadata_desc, section_desc, coverage_desc, ('',), |
| 279 group_desc) | 344 group_desc) |
| 280 | 345 |
| 281 def GenerateLines(self, obj): | 346 def GenerateLines(self, obj): |
| 282 if isinstance(obj, models.SizeInfoDiff): | 347 if isinstance(obj, models.DeltaSizeInfo): |
| 283 return self._DescribeSizeInfoDiff(obj) | 348 return self._DescribeDeltaSizeInfo(obj) |
| 284 if isinstance(obj, models.SizeInfo): | 349 if isinstance(obj, models.SizeInfo): |
| 285 return self._DescribeSizeInfo(obj) | 350 return self._DescribeSizeInfo(obj) |
| 286 if isinstance(obj, models.SymbolDiff): | 351 if isinstance(obj, models.DeltaSymbolGroup): |
| 287 return self._DescribeSymbolDiff(obj) | 352 return self._DescribeDeltaSymbolGroup(obj) |
| 288 if isinstance(obj, models.SymbolGroup): | 353 if isinstance(obj, models.SymbolGroup): |
| 289 return self._DescribeSymbolGroup(obj) | 354 return self._DescribeSymbolGroup(obj) |
| 290 if isinstance(obj, models.Symbol): | 355 if isinstance(obj, models.Symbol): |
| 291 return self._DescribeSymbol(obj) | 356 return self._DescribeSymbol(obj) |
| 292 return (repr(obj),) | 357 return (repr(obj),) |
| 293 | 358 |
| 294 | 359 |
| 295 def DescribeSizeInfoCoverage(size_info): | 360 def DescribeSizeInfoCoverage(size_info): |
| 296 """Yields lines describing how accurate |size_info| is.""" | 361 """Yields lines describing how accurate |size_info| is.""" |
| 297 for section in models.SECTION_TO_SECTION_NAME: | 362 for section in models.SECTION_TO_SECTION_NAME: |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 365 | 430 |
| 366 def GenerateLines(obj, verbose=False, recursive=False): | 431 def GenerateLines(obj, verbose=False, recursive=False): |
| 367 """Returns an iterable of lines (without \n) that describes |obj|.""" | 432 """Returns an iterable of lines (without \n) that describes |obj|.""" |
| 368 return Describer(verbose=verbose, recursive=recursive).GenerateLines(obj) | 433 return Describer(verbose=verbose, recursive=recursive).GenerateLines(obj) |
| 369 | 434 |
| 370 | 435 |
| 371 def WriteLines(lines, func): | 436 def WriteLines(lines, func): |
| 372 for l in lines: | 437 for l in lines: |
| 373 func(l) | 438 func(l) |
| 374 func('\n') | 439 func('\n') |
| OLD | NEW |