Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(52)

Side by Side Diff: tools/binary_size/libsupersize/archive.py

Issue 2833253002: supersize: Parse build.ninja concurrently (Closed)
Patch Set: tweak Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | tools/binary_size/libsupersize/helpers.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
11 import gzip 11 import gzip
12 import logging 12 import logging
13 import os 13 import os
14 import multiprocessing
15 import posixpath 14 import posixpath
16 import re 15 import re
17 import subprocess 16 import subprocess
18 import sys 17 import sys
19 import tempfile 18 import tempfile
20 import zipfile 19 import zipfile
21 20
22 import describe 21 import describe
23 import file_format 22 import file_format
24 import function_signature 23 import function_signature
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
148 def _NormalizeSourcePath(path): 147 def _NormalizeSourcePath(path):
149 if path.startswith('gen/'): 148 if path.startswith('gen/'):
150 # Convert gen/third_party/... -> third_party/... 149 # Convert gen/third_party/... -> third_party/...
151 return path[4:] 150 return path[4:]
152 if path.startswith('../../'): 151 if path.startswith('../../'):
153 # Convert ../../third_party/... -> third_party/... 152 # Convert ../../third_party/... -> third_party/...
154 return path[6:] 153 return path[6:]
155 return path 154 return path
156 155
157 156
158 def _ExtractSourcePaths(symbols, output_directory): 157 def _ExtractSourcePaths(symbols, source_mapper):
159 """Fills in the .source_path attribute of all symbols. 158 """Fills in the .source_path attribute of all symbols."""
160 159 logging.debug('Parsed %d .ninja files.', source_mapper.parsed_file_count)
161 Returns True if source paths were found.
162 """
163 mapper = ninja_parser.SourceFileMapper(output_directory)
164 not_found_paths = set()
165 160
166 for symbol in symbols: 161 for symbol in symbols:
167 object_path = symbol.object_path 162 object_path = symbol.object_path
168 if symbol.source_path or not object_path: 163 if symbol.source_path or not object_path:
169 continue 164 continue
170 # We don't have source info for prebuilt .a files. 165 # We don't have source info for prebuilt .a files.
171 if not os.path.isabs(object_path) and not object_path.startswith('..'): 166 if not os.path.isabs(object_path) and not object_path.startswith('..'):
172 source_path = mapper.FindSourceForPath(object_path) 167 source_path = source_mapper.FindSourceForPath(object_path)
173 if source_path: 168 if source_path:
174 symbol.source_path = _NormalizeSourcePath(source_path) 169 symbol.source_path = _NormalizeSourcePath(source_path)
175 elif object_path not in not_found_paths:
176 not_found_paths.add(object_path)
177 logging.warning('Could not find source path for %s', object_path)
178 logging.debug('Parsed %d .ninja files.', mapper.GetParsedFileCount())
179 return len(not_found_paths) == 0
180 170
181 171
182 def _CalculatePadding(symbols): 172 def _CalculatePadding(symbols):
183 """Populates the |padding| field based on symbol addresses. 173 """Populates the |padding| field based on symbol addresses.
184 174
185 Symbols must already be sorted by |address|. 175 Symbols must already be sorted by |address|.
186 """ 176 """
187 seen_sections = [] 177 seen_sections = []
188 for i, symbol in enumerate(symbols[1:]): 178 for i, symbol in enumerate(symbols[1:]):
189 prev_symbol = symbols[i] 179 prev_symbol = symbols[i]
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after
342 _CalculatePadding(size_info.raw_symbols) 332 _CalculatePadding(size_info.raw_symbols)
343 logging.info('Grouping decomposed functions') 333 logging.info('Grouping decomposed functions')
344 size_info.symbols = models.SymbolGroup( 334 size_info.symbols = models.SymbolGroup(
345 _ClusterSymbols(size_info.raw_symbols)) 335 _ClusterSymbols(size_info.raw_symbols))
346 logging.info('Processed %d symbols', len(size_info.raw_symbols)) 336 logging.info('Processed %d symbols', len(size_info.raw_symbols))
347 337
348 338
349 def CreateSizeInfo(map_path, lazy_paths=None, no_source_paths=False, 339 def CreateSizeInfo(map_path, lazy_paths=None, no_source_paths=False,
350 raw_only=False): 340 raw_only=False):
351 """Creates a SizeInfo from the given map file.""" 341 """Creates a SizeInfo from the given map file."""
352 if not no_source_paths:
353 # output_directory needed for source file information.
354 lazy_paths.VerifyOutputDirectory()
355 # tool_prefix needed for c++filt. 342 # tool_prefix needed for c++filt.
356 lazy_paths.VerifyToolPrefix() 343 lazy_paths.VerifyToolPrefix()
357 344
345 if not no_source_paths:
346 # Parse .ninja files at the same time as parsing the .map file.
347 source_mapper_result = helpers.ForkAndCall(
348 ninja_parser.Parse, lazy_paths.VerifyOutputDirectory())
349
358 with _OpenMaybeGz(map_path) as map_file: 350 with _OpenMaybeGz(map_path) as map_file:
359 section_sizes, raw_symbols = ( 351 section_sizes, raw_symbols = (
360 linker_map_parser.MapFileParser().Parse(map_file)) 352 linker_map_parser.MapFileParser().Parse(map_file))
361 353
362 if not no_source_paths: 354 if not no_source_paths:
363 logging.info('Extracting source paths from .ninja files') 355 logging.info('Extracting source paths from .ninja files')
364 all_found = _ExtractSourcePaths(raw_symbols, lazy_paths.output_directory) 356 source_mapper = source_mapper_result.get()
365 assert all_found, ( 357 _ExtractSourcePaths(raw_symbols, source_mapper)
358 assert source_mapper.unmatched_paths_count == 0, (
366 'One or more source file paths could not be found. Likely caused by ' 359 'One or more source file paths could not be found. Likely caused by '
367 '.ninja files being generated at a different time than the .map file.') 360 '.ninja files being generated at a different time than the .map file.')
368 361
369 logging.info('Stripping linker prefixes from symbol names') 362 logging.info('Stripping linker prefixes from symbol names')
370 _StripLinkerAddedSymbolPrefixes(raw_symbols) 363 _StripLinkerAddedSymbolPrefixes(raw_symbols)
371 # Map file for some reason doesn't unmangle all names. 364 # Map file for some reason doesn't unmangle all names.
372 # Unmangle prints its own log statement. 365 # Unmangle prints its own log statement.
373 _UnmangleRemainingSymbols(raw_symbols, lazy_paths.tool_prefix) 366 _UnmangleRemainingSymbols(raw_symbols, lazy_paths.tool_prefix)
374 logging.info('Normalizing object paths') 367 logging.info('Normalizing object paths')
375 _NormalizeObjectPaths(raw_symbols) 368 _NormalizeObjectPaths(raw_symbols)
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after
531 models.METADATA_ELF_ARCHITECTURE: architecture, 524 models.METADATA_ELF_ARCHITECTURE: architecture,
532 models.METADATA_ELF_FILENAME: relative_to_out(elf_path), 525 models.METADATA_ELF_FILENAME: relative_to_out(elf_path),
533 models.METADATA_ELF_MTIME: timestamp, 526 models.METADATA_ELF_MTIME: timestamp,
534 models.METADATA_ELF_BUILD_ID: build_id, 527 models.METADATA_ELF_BUILD_ID: build_id,
535 models.METADATA_GN_ARGS: gn_args, 528 models.METADATA_GN_ARGS: gn_args,
536 } 529 }
537 530
538 if apk_path: 531 if apk_path:
539 metadata[models.METADATA_APK_FILENAME] = relative_to_out(apk_path) 532 metadata[models.METADATA_APK_FILENAME] = relative_to_out(apk_path)
540 # Extraction takes around 1 second, so do it in parallel. 533 # Extraction takes around 1 second, so do it in parallel.
541 pool_of_one = multiprocessing.Pool(1) 534 apk_elf_result = helpers.ForkAndCall(
542 apk_elf_result = pool_of_one.apply_async( 535 _ElfInfoFromApk, apk_path, apk_so_path, lazy_paths.tool_prefix)
543 _ElfInfoFromApk, (apk_path, apk_so_path, lazy_paths.tool_prefix))
544 pool_of_one.close()
545 536
546 size_info = CreateSizeInfo( 537 size_info = CreateSizeInfo(
547 map_path, lazy_paths, no_source_paths=args.no_source_paths, raw_only=True) 538 map_path, lazy_paths, no_source_paths=args.no_source_paths, raw_only=True)
548 539
549 if metadata: 540 if metadata:
550 size_info.metadata = metadata 541 size_info.metadata = metadata
551 logging.debug('Validating section sizes') 542 logging.debug('Validating section sizes')
552 elf_section_sizes = _SectionSizesFromElf(elf_path, lazy_paths.tool_prefix) 543 elf_section_sizes = _SectionSizesFromElf(elf_path, lazy_paths.tool_prefix)
553 for k, v in elf_section_sizes.iteritems(): 544 for k, v in elf_section_sizes.iteritems():
554 assert v == size_info.section_sizes.get(k), ( 545 assert v == size_info.section_sizes.get(k), (
(...skipping 19 matching lines...) Expand all
574 logging.warning('Packed section not present: %s', packed_section_name) 565 logging.warning('Packed section not present: %s', packed_section_name)
575 else: 566 else:
576 size_info.section_sizes['%s (unpacked)' % packed_section_name] = ( 567 size_info.section_sizes['%s (unpacked)' % packed_section_name] = (
577 unstripped_section_sizes.get(packed_section_name)) 568 unstripped_section_sizes.get(packed_section_name))
578 569
579 logging.info('Recording metadata: \n %s', 570 logging.info('Recording metadata: \n %s',
580 '\n '.join(describe.DescribeMetadata(size_info.metadata))) 571 '\n '.join(describe.DescribeMetadata(size_info.metadata)))
581 logging.info('Saving result to %s', args.size_file) 572 logging.info('Saving result to %s', args.size_file)
582 file_format.SaveSizeInfo(size_info, args.size_file) 573 file_format.SaveSizeInfo(size_info, args.size_file)
583 logging.info('Done') 574 logging.info('Done')
OLDNEW
« no previous file with comments | « no previous file | tools/binary_size/libsupersize/helpers.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698