Chromium Code Reviews| Index: build/android/resource_sizes.py |
| diff --git a/build/android/resource_sizes.py b/build/android/resource_sizes.py |
| index 6f531f052d764884f80eab68525b518591fe8637..e0a733d76d98f11899523f2f8bc3fa2288f1c246 100755 |
| --- a/build/android/resource_sizes.py |
| +++ b/build/android/resource_sizes.py |
| @@ -10,13 +10,13 @@ |
| """ |
| import collections |
| +from contextlib import contextmanager |
| import json |
| import logging |
| import operator |
| import optparse |
| import os |
| import re |
| -import shutil |
| import struct |
| import sys |
| import tempfile |
| @@ -33,6 +33,8 @@ from pylib.constants import host_paths |
| _AAPT_PATH = lazy.WeakConstant(lambda: build_tools.GetPath('aapt')) |
| _GRIT_PATH = os.path.join(host_paths.DIR_SOURCE_ROOT, 'tools', 'grit') |
| +_BUILD_UTILS_PATH = os.path.join( |
| + host_paths.DIR_SOURCE_ROOT, 'build', 'android', 'gyp') |
| # Prepend the grit module from the source tree so it takes precedence over other |
| # grit versions that might present in the search path. |
| @@ -42,6 +44,9 @@ with host_paths.SysPath(_GRIT_PATH, 1): |
| with host_paths.SysPath(host_paths.BUILD_COMMON_PATH): |
| import perf_tests_results_helper # pylint: disable=import-error |
| +with host_paths.SysPath(_BUILD_UTILS_PATH, 1): |
| + from util import build_utils # pylint: disable=import-error |
| + |
| # Python had a bug in zipinfo parsing that triggers on ChromeModern.apk |
| # https://bugs.python.org/issue14315 |
| @@ -115,26 +120,20 @@ _READELF_SIZES_METRICS = { |
| def _ExtractMainLibSectionSizesFromApk(apk_path, main_lib_path): |
| - tmpdir = tempfile.mkdtemp(suffix='_apk_extract') |
| - grouped_section_sizes = collections.defaultdict(int) |
| - try: |
| - with zipfile.ZipFile(apk_path, 'r') as z: |
| - extracted_lib_path = z.extract(main_lib_path, tmpdir) |
| - section_sizes = _CreateSectionNameSizeMap(extracted_lib_path) |
| - |
| - for group_name, section_names in _READELF_SIZES_METRICS.iteritems(): |
| - for section_name in section_names: |
| - if section_name in section_sizes: |
| - grouped_section_sizes[group_name] += section_sizes.pop(section_name) |
| + with Unzip(apk_path, pattern=main_lib_path) as extracted_lib_path: |
| + grouped_section_sizes = collections.defaultdict(int) |
| + section_sizes = _CreateSectionNameSizeMap(extracted_lib_path) |
| + for group_name, section_names in _READELF_SIZES_METRICS.iteritems(): |
| + for section_name in section_names: |
| + if section_name in section_sizes: |
| + grouped_section_sizes[group_name] += section_sizes.pop(section_name) |
| - # Group any unknown section headers into the "other" group. |
| - for section_header, section_size in section_sizes.iteritems(): |
| - print "Unknown elf section header:", section_header |
| - grouped_section_sizes['other'] += section_size |
| + # Group any unknown section headers into the "other" group. |
| + for section_header, section_size in section_sizes.iteritems(): |
| + print "Unknown elf section header:", section_header |
| + grouped_section_sizes['other'] += section_size |
| - return grouped_section_sizes |
| - finally: |
| - shutil.rmtree(tmpdir) |
| + return grouped_section_sizes |
| def _CreateSectionNameSizeMap(so_path): |
| @@ -148,6 +147,13 @@ def _CreateSectionNameSizeMap(so_path): |
| return section_sizes |
| +def _ParseLibBuildId(so_path): |
| + """Returns the Build ID of the given native library.""" |
| + stdout = cmd_helper.GetCmdOutput(['readelf', '-n', so_path]) |
| + match = re.search(r'Build ID: (\w{40})', stdout) |
|
agrieve
2017/02/24 20:04:21
nit: BuildIDs don't need to be 40 characters (alth
estevenson
2017/02/28 00:58:45
Left it in. Done.
|
| + return match.group(1) if match else None |
| + |
| + |
| def CountStaticInitializers(so_path): |
| # Static initializers expected in official builds. Note that this list is |
| # built using 'nm' on libchrome.so which results from a GCC official build |
| @@ -595,7 +601,8 @@ def _PrintStaticInitializersCountFromApk(apk_filename, chartjson=None): |
| lib_name = os.path.basename(zip_info.filename).replace('crazy.', '') |
| unstripped_path = os.path.join(out_dir, 'lib.unstripped', lib_name) |
| if os.path.exists(unstripped_path): |
| - si_count += _PrintStaticInitializersCount(unstripped_path) |
| + si_count += _PrintStaticInitializersCount( |
| + apk_filename, zip_info.filename, unstripped_path) |
| else: |
| raise Exception('Unstripped .so not found. Looked here: %s', |
| unstripped_path) |
| @@ -603,21 +610,24 @@ def _PrintStaticInitializersCountFromApk(apk_filename, chartjson=None): |
| 'count') |
| -def _PrintStaticInitializersCount(so_with_symbols_path): |
| +def _PrintStaticInitializersCount(apk_path, apk_so_name, so_with_symbols_path): |
| """Counts the number of static initializers in the given shared library. |
| Additionally, files for which static initializers were found are printed |
| on the standard output. |
| Args: |
| - so_with_symbols_path: Path to the unstripped libchrome.so file. |
| - |
| + apk_path: Path to the apk. |
| + apk_so_name: Name of the so. |
| + so_with_symbols_path: Path to the unstripped libchrome.so file. |
| Returns: |
| The number of static initializers found. |
| """ |
| # GetStaticInitializers uses get-static-initializers.py to get a list of all |
| # static initializers. This does not work on all archs (particularly arm). |
| # TODO(rnephew): Get rid of warning when crbug.com/585588 is fixed. |
| - si_count = CountStaticInitializers(so_with_symbols_path) |
| + with Unzip(apk_path, pattern="*%s" % apk_so_name) as unzipped_so: |
| + _VerifyLibBuildIdsMatch(unzipped_so, so_with_symbols_path) |
| + si_count = CountStaticInitializers(unzipped_so) |
| static_initializers = GetStaticInitializers(so_with_symbols_path) |
| static_initializers_count = len(static_initializers) - 1 # Minus summary. |
| if si_count != static_initializers_count: |
| @@ -666,6 +676,21 @@ def _PrintDexAnalysis(apk_filename, chartjson=None): |
| 'bytes') |
| +@contextmanager |
| +def Unzip(zip_file, pattern=None, predicate=None): |
| + """Utility for temporary use of a set of files in a zip archive.""" |
| + with build_utils.TempDir() as unzipped_dir: |
| + unzipped_files = build_utils.ExtractAll( |
| + zip_file, unzipped_dir, True, pattern=pattern, predicate=predicate) |
| + yield unzipped_files[0] if len(unzipped_files) == 1 else unzipped_files |
| + |
| + |
| +def _VerifyLibBuildIdsMatch(*so_files): |
| + if len(set(_ParseLibBuildId(f) for f in so_files)) > 1: |
| + raise Exception('Found differing build ids in output directory and apk. ' |
| + 'Your output directory is likely stale.') |
| + |
| + |
| def main(argv): |
| usage = """Usage: %prog [options] file1 file2 ... |
| @@ -713,11 +738,6 @@ Pass any number of files to graph their sizes. Any files with the extension |
| if not files: |
| option_parser.error('Must specify a file') |
| - if options.so_with_symbols_path: |
| - si_count = _PrintStaticInitializersCount(options.so_with_symbols_path) |
| - ReportPerfResult(chartjson, 'StaticInitializersCount', 'count', si_count, |
| - 'count') |
| - |
| PrintResourceSizes(files, chartjson=chartjson) |
| for f in files: |
| @@ -726,7 +746,13 @@ Pass any number of files to graph their sizes. Any files with the extension |
| _PrintDexAnalysis(f, chartjson=chartjson) |
| if not options.no_output_dir: |
| PrintPakAnalysis(f, options.min_pak_resource_size) |
| - if not options.so_with_symbols_path: |
| + so_path = options.so_with_symbols_path |
|
agrieve
2017/02/24 20:04:21
This actually makes less sense inside the loop. Ho
estevenson
2017/02/28 00:58:45
I removed obsolete args and changed the script to
|
| + if so_path: |
| + si_count = _PrintStaticInitializersCount( |
| + f, os.path.basename(so_path), so_path) |
| + ReportPerfResult( |
| + chartjson, 'StaticInitializersCount', 'count', si_count, 'count') |
| + else: |
| _PrintStaticInitializersCountFromApk(f, chartjson=chartjson) |
| if chartjson: |