| 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 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 136 # Convert ../../third_party/... -> third_party/... | 136 # Convert ../../third_party/... -> third_party/... |
| 137 path = path[6:] | 137 path = path[6:] |
| 138 if path.endswith(')'): | 138 if path.endswith(')'): |
| 139 # Convert foo/bar.a(baz.o) -> foo/bar.a/baz.o | 139 # Convert foo/bar.a(baz.o) -> foo/bar.a/baz.o |
| 140 start_idx = path.index('(') | 140 start_idx = path.index('(') |
| 141 path = os.path.join(path[:start_idx], path[start_idx + 1:-1]) | 141 path = os.path.join(path[:start_idx], path[start_idx + 1:-1]) |
| 142 return path | 142 return path |
| 143 | 143 |
| 144 | 144 |
| 145 def _NormalizeSourcePath(path): | 145 def _NormalizeSourcePath(path): |
| 146 """Returns (is_generated, normalized_path)""" |
| 146 if path.startswith('gen/'): | 147 if path.startswith('gen/'): |
| 147 # Convert gen/third_party/... -> third_party/... | 148 # Convert gen/third_party/... -> third_party/... |
| 148 return path[4:] | 149 return True, path[4:] |
| 149 if path.startswith('../../'): | 150 if path.startswith('../../'): |
| 150 # Convert ../../third_party/... -> third_party/... | 151 # Convert ../../third_party/... -> third_party/... |
| 151 return path[6:] | 152 return False, path[6:] |
| 152 return path | 153 return True, path |
| 153 | 154 |
| 154 | 155 |
| 155 def _SourcePathForObjectPath(object_path, source_mapper): | 156 def _SourcePathForObjectPath(object_path, source_mapper): |
| 157 """Returns (is_generated, normalized_path)""" |
| 156 # We don't have source info for prebuilt .a files. | 158 # We don't have source info for prebuilt .a files. |
| 157 if not os.path.isabs(object_path) and not object_path.startswith('..'): | 159 if not os.path.isabs(object_path) and not object_path.startswith('..'): |
| 158 source_path = source_mapper.FindSourceForPath(object_path) | 160 source_path = source_mapper.FindSourceForPath(object_path) |
| 159 if source_path: | 161 if source_path: |
| 160 return _NormalizeSourcePath(source_path) | 162 return _NormalizeSourcePath(source_path) |
| 161 return '' | 163 return False, '' |
| 162 | 164 |
| 163 | 165 |
| 164 def _ExtractSourcePaths(raw_symbols, source_mapper): | 166 def _ExtractSourcePaths(raw_symbols, source_mapper): |
| 165 """Fills in the |source_path| attribute.""" | 167 """Fills in the |source_path| attribute.""" |
| 166 logging.debug('Parsed %d .ninja files.', source_mapper.parsed_file_count) | 168 logging.debug('Parsed %d .ninja files.', source_mapper.parsed_file_count) |
| 167 for symbol in raw_symbols: | 169 for symbol in raw_symbols: |
| 168 object_path = symbol.object_path | 170 object_path = symbol.object_path |
| 169 if object_path and not symbol.source_path: | 171 if object_path and not symbol.source_path: |
| 170 symbol.source_path = _SourcePathForObjectPath(object_path, source_mapper) | 172 symbol.generated_source, symbol.source_path = ( |
| 173 _SourcePathForObjectPath(object_path, source_mapper)) |
| 171 | 174 |
| 172 | 175 |
| 173 def _ComputeAnscestorPath(path_list): | 176 def _ComputeAnscestorPath(path_list): |
| 174 """Returns the common anscestor of the given paths.""" | 177 """Returns the common anscestor of the given paths.""" |
| 175 # Ignore missing paths. | 178 # Ignore missing paths. |
| 176 path_list = [p for p in path_list if p] | 179 path_list = [p for p in path_list if p] |
| 177 prefix = os.path.commonprefix(path_list) | 180 prefix = os.path.commonprefix(path_list) |
| 178 # Put the path count as a subdirectory to allow for better grouping when | 181 # Put the path count as a subdirectory to allow for better grouping when |
| 179 # path-based breakdowns. | 182 # path-based breakdowns. |
| 180 if not prefix: | 183 if not prefix: |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 224 continue | 227 continue |
| 225 | 228 |
| 226 if symbol.object_path and symbol.object_path not in object_paths: | 229 if symbol.object_path and symbol.object_path not in object_paths: |
| 227 if num_path_mismatches < 10: | 230 if num_path_mismatches < 10: |
| 228 logging.warning('Symbol path reported by .map not found by nm.') | 231 logging.warning('Symbol path reported by .map not found by nm.') |
| 229 logging.warning('sym=%r', symbol) | 232 logging.warning('sym=%r', symbol) |
| 230 logging.warning('paths=%r', object_paths) | 233 logging.warning('paths=%r', object_paths) |
| 231 num_path_mismatches += 1 | 234 num_path_mismatches += 1 |
| 232 | 235 |
| 233 if source_mapper: | 236 if source_mapper: |
| 234 source_paths = [ | 237 tups = [ |
| 235 _SourcePathForObjectPath(p, source_mapper) for p in object_paths] | 238 _SourcePathForObjectPath(p, source_mapper) for p in object_paths] |
| 236 symbol.source_path = _ComputeAnscestorPath(source_paths) | 239 symbol.source_path = _ComputeAnscestorPath(t[1] for t in tups) |
| 240 symbol.generated_source = all(t[0] for t in tups) |
| 237 | 241 |
| 238 object_paths = [_NormalizeObjectPath(p) for p in object_paths] | 242 object_paths = [_NormalizeObjectPath(p) for p in object_paths] |
| 239 symbol.object_path = _ComputeAnscestorPath(object_paths) | 243 symbol.object_path = _ComputeAnscestorPath(object_paths) |
| 240 | 244 |
| 241 logging.debug('Cross-referenced %d symbols with nm output. ' | 245 logging.debug('Cross-referenced %d symbols with nm output. ' |
| 242 'num_unknown_names=%d num_path_mismatches=%d ' | 246 'num_unknown_names=%d num_path_mismatches=%d ' |
| 243 'num_unused_aliases=%d', num_found_paths, num_unknown_names, | 247 'num_unused_aliases=%d', num_found_paths, num_unknown_names, |
| 244 num_path_mismatches, num_unmatched_aliases) | 248 num_path_mismatches, num_unmatched_aliases) |
| 245 | 249 |
| 246 | 250 |
| (...skipping 424 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 671 logging.warning('Packed section not present: %s', packed_section_name) | 675 logging.warning('Packed section not present: %s', packed_section_name) |
| 672 else: | 676 else: |
| 673 size_info.section_sizes['%s (unpacked)' % packed_section_name] = ( | 677 size_info.section_sizes['%s (unpacked)' % packed_section_name] = ( |
| 674 unstripped_section_sizes.get(packed_section_name)) | 678 unstripped_section_sizes.get(packed_section_name)) |
| 675 | 679 |
| 676 logging.info('Recording metadata: \n %s', | 680 logging.info('Recording metadata: \n %s', |
| 677 '\n '.join(describe.DescribeMetadata(size_info.metadata))) | 681 '\n '.join(describe.DescribeMetadata(size_info.metadata))) |
| 678 logging.info('Saving result to %s', args.size_file) | 682 logging.info('Saving result to %s', args.size_file) |
| 679 file_format.SaveSizeInfo(size_info, args.size_file) | 683 file_format.SaveSizeInfo(size_info, args.size_file) |
| 680 logging.info('Done') | 684 logging.info('Done') |
| OLD | NEW |