| 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 | 4 |
| 5 """Main Python API for analyzing binary size.""" | 5 """Main Python API for analyzing binary size.""" |
| 6 | 6 |
| 7 import argparse | 7 import argparse |
| 8 import calendar | 8 import calendar |
| 9 import collections | 9 import collections |
| 10 import datetime | 10 import datetime |
| (...skipping 20 matching lines...) Expand all Loading... |
| 31 | 31 |
| 32 def _OpenMaybeGz(path, mode=None): | 32 def _OpenMaybeGz(path, mode=None): |
| 33 """Calls `gzip.open()` if |path| ends in ".gz", otherwise calls `open()`.""" | 33 """Calls `gzip.open()` if |path| ends in ".gz", otherwise calls `open()`.""" |
| 34 if path.endswith('.gz'): | 34 if path.endswith('.gz'): |
| 35 if mode and 'w' in mode: | 35 if mode and 'w' in mode: |
| 36 return gzip.GzipFile(path, mode, 1) | 36 return gzip.GzipFile(path, mode, 1) |
| 37 return gzip.open(path, mode) | 37 return gzip.open(path, mode) |
| 38 return open(path, mode or 'r') | 38 return open(path, mode or 'r') |
| 39 | 39 |
| 40 | 40 |
| 41 def _StripLinkerAddedSymbolPrefixes(symbols): |
| 42 """Removes prefixes sometimes added to symbol names during link |
| 43 |
| 44 Removing prefixes make symbol names match up with those found in .o files. |
| 45 """ |
| 46 for symbol in symbols: |
| 47 name = symbol.name |
| 48 if name.startswith('startup.'): |
| 49 symbol.flags |= models.FLAG_STARTUP |
| 50 symbol.name = name[8:] |
| 51 elif name.startswith('unlikely.'): |
| 52 symbol.flags |= models.FLAG_UNLIKELY |
| 53 symbol.name = name[9:] |
| 54 elif name.startswith('rel.local.'): |
| 55 symbol.flags |= models.FLAG_REL_LOCAL |
| 56 symbol.name = name[10:] |
| 57 elif name.startswith('rel.'): |
| 58 symbol.flags |= models.FLAG_REL |
| 59 symbol.name = name[4:] |
| 60 |
| 61 |
| 41 def _UnmangleRemainingSymbols(symbols, tool_prefix): | 62 def _UnmangleRemainingSymbols(symbols, tool_prefix): |
| 42 """Uses c++filt to unmangle any symbols that need it.""" | 63 """Uses c++filt to unmangle any symbols that need it.""" |
| 43 to_process = [s for s in symbols if s.name.startswith('_Z')] | 64 to_process = [s for s in symbols if s.name.startswith('_Z')] |
| 44 if not to_process: | 65 if not to_process: |
| 45 return | 66 return |
| 46 | 67 |
| 47 logging.info('Unmangling %d names', len(to_process)) | 68 logging.info('Unmangling %d names', len(to_process)) |
| 48 proc = subprocess.Popen([tool_prefix + 'c++filt'], stdin=subprocess.PIPE, | 69 proc = subprocess.Popen([tool_prefix + 'c++filt'], stdin=subprocess.PIPE, |
| 49 stdout=subprocess.PIPE) | 70 stdout=subprocess.PIPE) |
| 50 stdout = proc.communicate('\n'.join(s.name for s in to_process))[0] | 71 stdout = proc.communicate('\n'.join(s.name for s in to_process))[0] |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 82 found_prefixes.add(symbol.name[:idx + 3]) | 103 found_prefixes.add(symbol.name[:idx + 3]) |
| 83 symbol.name = symbol.name[idx + 4:] + ' [' + symbol.name[:idx] + ']' | 104 symbol.name = symbol.name[idx + 4:] + ' [' + symbol.name[:idx] + ']' |
| 84 | 105 |
| 85 # Strip out return type, and identify where parameter list starts. | 106 # Strip out return type, and identify where parameter list starts. |
| 86 if symbol.section == 't': | 107 if symbol.section == 't': |
| 87 symbol.full_name, symbol.name = function_signature.Parse(symbol.name) | 108 symbol.full_name, symbol.name = function_signature.Parse(symbol.name) |
| 88 | 109 |
| 89 # Remove anonymous namespaces (they just harm clustering). | 110 # Remove anonymous namespaces (they just harm clustering). |
| 90 non_anonymous = symbol.name.replace('(anonymous namespace)::', '') | 111 non_anonymous = symbol.name.replace('(anonymous namespace)::', '') |
| 91 if symbol.name != non_anonymous: | 112 if symbol.name != non_anonymous: |
| 92 symbol.is_anonymous = True | 113 symbol.flags |= models.FLAG_ANONYMOUS |
| 93 symbol.name = non_anonymous | 114 symbol.name = non_anonymous |
| 94 symbol.full_name = symbol.full_name.replace( | 115 symbol.full_name = symbol.full_name.replace( |
| 95 '(anonymous namespace)::', '') | 116 '(anonymous namespace)::', '') |
| 96 | 117 |
| 97 if symbol.section != 't' and '(' in symbol.name: | 118 if symbol.section != 't' and '(' in symbol.name: |
| 98 # Pretty rare. Example: | 119 # Pretty rare. Example: |
| 99 # blink::CSSValueKeywordsHash::findValueImpl(char const*)::value_word_list | 120 # blink::CSSValueKeywordsHash::findValueImpl(char const*)::value_word_list |
| 100 symbol.full_name = symbol.name | 121 symbol.full_name = symbol.name |
| 101 symbol.name = re.sub(r'\(.*\)', '', symbol.full_name) | 122 symbol.name = re.sub(r'\(.*\)', '', symbol.full_name) |
| 102 | 123 |
| (...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 337 with _OpenMaybeGz(map_path) as map_file: | 358 with _OpenMaybeGz(map_path) as map_file: |
| 338 section_sizes, raw_symbols = ( | 359 section_sizes, raw_symbols = ( |
| 339 linker_map_parser.MapFileParser().Parse(map_file)) | 360 linker_map_parser.MapFileParser().Parse(map_file)) |
| 340 | 361 |
| 341 if not no_source_paths: | 362 if not no_source_paths: |
| 342 logging.info('Extracting source paths from .ninja files') | 363 logging.info('Extracting source paths from .ninja files') |
| 343 all_found = _ExtractSourcePaths(raw_symbols, lazy_paths.output_directory) | 364 all_found = _ExtractSourcePaths(raw_symbols, lazy_paths.output_directory) |
| 344 assert all_found, ( | 365 assert all_found, ( |
| 345 'One or more source file paths could not be found. Likely caused by ' | 366 'One or more source file paths could not be found. Likely caused by ' |
| 346 '.ninja files being generated at a different time than the .map file.') | 367 '.ninja files being generated at a different time than the .map file.') |
| 368 |
| 369 logging.info('Stripping linker prefixes from symbol names') |
| 370 _StripLinkerAddedSymbolPrefixes(raw_symbols) |
| 347 # Map file for some reason doesn't unmangle all names. | 371 # Map file for some reason doesn't unmangle all names. |
| 348 # Unmangle prints its own log statement. | 372 # Unmangle prints its own log statement. |
| 349 _UnmangleRemainingSymbols(raw_symbols, lazy_paths.tool_prefix) | 373 _UnmangleRemainingSymbols(raw_symbols, lazy_paths.tool_prefix) |
| 350 logging.info('Normalizing object paths') | 374 logging.info('Normalizing object paths') |
| 351 _NormalizeObjectPaths(raw_symbols) | 375 _NormalizeObjectPaths(raw_symbols) |
| 352 size_info = models.SizeInfo(section_sizes, raw_symbols) | 376 size_info = models.SizeInfo(section_sizes, raw_symbols) |
| 353 | 377 |
| 354 # Name normalization not strictly required, but makes for smaller files. | 378 # Name normalization not strictly required, but makes for smaller files. |
| 355 if raw_only: | 379 if raw_only: |
| 356 logging.info('Normalizing symbol names') | 380 logging.info('Normalizing symbol names') |
| (...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 550 logging.warning('Packed section not present: %s', packed_section_name) | 574 logging.warning('Packed section not present: %s', packed_section_name) |
| 551 else: | 575 else: |
| 552 size_info.section_sizes['%s (unpacked)' % packed_section_name] = ( | 576 size_info.section_sizes['%s (unpacked)' % packed_section_name] = ( |
| 553 unstripped_section_sizes.get(packed_section_name)) | 577 unstripped_section_sizes.get(packed_section_name)) |
| 554 | 578 |
| 555 logging.info('Recording metadata: \n %s', | 579 logging.info('Recording metadata: \n %s', |
| 556 '\n '.join(describe.DescribeMetadata(size_info.metadata))) | 580 '\n '.join(describe.DescribeMetadata(size_info.metadata))) |
| 557 logging.info('Saving result to %s', args.size_file) | 581 logging.info('Saving result to %s', args.size_file) |
| 558 file_format.SaveSizeInfo(size_info, args.size_file) | 582 file_format.SaveSizeInfo(size_info, args.size_file) |
| 559 logging.info('Done') | 583 logging.info('Done') |
| OLD | NEW |