Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 """Prints the size of each given file and optionally computes the size of | 6 """Prints the size of each given file and optionally computes the size of |
| 7 libchrome.so without the dependencies added for building with android NDK. | 7 libchrome.so without the dependencies added for building with android NDK. |
| 8 Also breaks down the contents of the APK to determine the installed size | 8 Also breaks down the contents of the APK to determine the installed size |
| 9 and assign size contributions to different classes of file. | 9 and assign size contributions to different classes of file. |
| 10 """ | 10 """ |
| 11 | 11 |
| 12 import collections | 12 import collections |
| 13 import json | 13 import json |
| 14 import logging | 14 import logging |
| 15 import operator | 15 import operator |
| 16 import optparse | 16 import optparse |
| 17 import os | 17 import os |
| 18 import re | 18 import re |
| 19 import shutil | |
| 19 import struct | 20 import struct |
| 20 import sys | 21 import sys |
| 21 import tempfile | 22 import tempfile |
| 22 import zipfile | 23 import zipfile |
| 23 import zlib | 24 import zlib |
| 24 | 25 |
| 25 import devil_chromium | 26 import devil_chromium |
| 26 from devil.android.sdk import build_tools | 27 from devil.android.sdk import build_tools |
| 27 from devil.utils import cmd_helper | 28 from devil.utils import cmd_helper |
| 28 from devil.utils import lazy | 29 from devil.utils import lazy |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 92 'benchmark_name': 'resource_sizes', | 93 'benchmark_name': 'resource_sizes', |
| 93 'benchmark_description': 'APK resource size information.', | 94 'benchmark_description': 'APK resource size information.', |
| 94 'trace_rerun_options': [], | 95 'trace_rerun_options': [], |
| 95 'charts': {} | 96 'charts': {} |
| 96 } | 97 } |
| 97 _DUMP_STATIC_INITIALIZERS_PATH = os.path.join( | 98 _DUMP_STATIC_INITIALIZERS_PATH = os.path.join( |
| 98 host_paths.DIR_SOURCE_ROOT, 'tools', 'linux', 'dump-static-initializers.py') | 99 host_paths.DIR_SOURCE_ROOT, 'tools', 'linux', 'dump-static-initializers.py') |
| 99 # Pragma exists when enable_resource_whitelist_generation=true. | 100 # Pragma exists when enable_resource_whitelist_generation=true. |
| 100 _RC_HEADER_RE = re.compile( | 101 _RC_HEADER_RE = re.compile( |
| 101 r'^#define (?P<name>\w+) (?:_Pragma\(.*?\) )?(?P<id>\d+)$') | 102 r'^#define (?P<name>\w+) (?:_Pragma\(.*?\) )?(?P<id>\d+)$') |
| 103 _READELF_EXCLUDED_SECTIONS = ['.bss'] | |
|
agrieve
2017/02/02 21:41:44
nit: I'm not sure why I suggested not including th
| |
| 104 _READELF_SIZES_METRICS = { | |
| 105 'text': ['.text'], | |
| 106 'data': ['.data', '.rodata'], | |
| 107 'relocations': ['.rel.dyn', '.rel.plt', '.data.rel.ro', '.data.rel.ro.loca'], | |
| 108 'unwind': ['.ARM.extab', '.ARM.exidx'], | |
| 109 'symbols': ['.dynsym', '.dynstr', '.dynamic', '.shstrtab', '.got', '.plt'], | |
| 110 # Group any section headers not listed above into the "other" group in case | |
| 111 # section headers change over time. | |
| 112 # 'other': ['.hash', '.init_array', '.fini_array', '.comment', | |
| 113 # '.note.gnu.gold-ve', '.ARM.attributes', '.note.gnu.build-i', | |
| 114 # '.gnu.version', '.gnu.version_d', '.gnu.version_r'] | |
| 115 } | |
| 116 | |
| 117 | |
| 118 def _ExtractMainLibSectionSizesFromApk(apk_path, main_lib_path): | |
| 119 tmpdir = tempfile.mkdtemp(suffix='_apk_extract') | |
| 120 grouped_section_sizes = collections.defaultdict(int) | |
| 121 try: | |
| 122 with zipfile.ZipFile(apk_path, 'r') as z: | |
| 123 extracted_lib_path = z.extract(main_lib_path, tmpdir) | |
| 124 section_sizes = _CreateSectionNameSizeMap(extracted_lib_path) | |
| 125 | |
| 126 for group_name, section_names in _READELF_SIZES_METRICS.iteritems(): | |
| 127 for section_name in section_names: | |
| 128 grouped_section_sizes[group_name] += section_sizes.pop(section_name) | |
| 129 | |
| 130 grouped_section_sizes['other'] = sum( | |
| 131 size for section_name, size in section_sizes.iteritems() | |
| 132 if section_name not in _READELF_EXCLUDED_SECTIONS) | |
| 133 | |
| 134 return grouped_section_sizes | |
| 135 finally: | |
| 136 shutil.rmtree(tmpdir) | |
| 137 | |
| 138 | |
| 139 def _CreateSectionNameSizeMap(so_path): | |
| 140 stdout = cmd_helper.GetCmdOutput(['readelf', '-S', so_path]) | |
| 141 section_sizes = {} | |
| 142 # Matches [ 2] .dynsym DYNSYM 00000158 000158 004f70 10 A 3 1 4 | |
| 143 for match in re.finditer(r'\[[\s\d]+\] (\..*)$', stdout, re.MULTILINE): | |
| 144 items = match.group(1).split() | |
| 145 section_sizes[items[0]] = int(items[4], 16) | |
| 146 | |
| 147 return section_sizes | |
| 102 | 148 |
| 103 | 149 |
| 104 def CountStaticInitializers(so_path): | 150 def CountStaticInitializers(so_path): |
| 105 # Static initializers expected in official builds. Note that this list is | 151 # Static initializers expected in official builds. Note that this list is |
| 106 # built using 'nm' on libchrome.so which results from a GCC official build | 152 # built using 'nm' on libchrome.so which results from a GCC official build |
| 107 # (i.e. Clang is not supported currently). | 153 # (i.e. Clang is not supported currently). |
| 108 def get_elf_section_size(readelf_stdout, section_name): | 154 def get_elf_section_size(readelf_stdout, section_name): |
| 109 # Matches: .ctors PROGBITS 000000000516add0 5169dd0 000010 00 WA 0 0 8 | 155 # Matches: .ctors PROGBITS 000000000516add0 5169dd0 000010 00 WA 0 0 8 |
| 110 match = re.search(r'\.%s.*$' % re.escape(section_name), | 156 match = re.search(r'\.%s.*$' % re.escape(section_name), |
| 111 readelf_stdout, re.MULTILINE) | 157 readelf_stdout, re.MULTILINE) |
| (...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 358 # Size of main .so vs remaining. | 404 # Size of main .so vs remaining. |
| 359 main_lib_info = native_code.FindLargest() | 405 main_lib_info = native_code.FindLargest() |
| 360 if main_lib_info: | 406 if main_lib_info: |
| 361 main_lib_size = main_lib_info.file_size | 407 main_lib_size = main_lib_info.file_size |
| 362 ReportPerfResult(chartjson, apk_basename + '_Specifics', | 408 ReportPerfResult(chartjson, apk_basename + '_Specifics', |
| 363 'main lib size', main_lib_size, 'bytes') | 409 'main lib size', main_lib_size, 'bytes') |
| 364 secondary_size = native_code.ComputeUncompressedSize() - main_lib_size | 410 secondary_size = native_code.ComputeUncompressedSize() - main_lib_size |
| 365 ReportPerfResult(chartjson, apk_basename + '_Specifics', | 411 ReportPerfResult(chartjson, apk_basename + '_Specifics', |
| 366 'other lib size', secondary_size, 'bytes') | 412 'other lib size', secondary_size, 'bytes') |
| 367 | 413 |
| 414 main_lib_section_sizes = _ExtractMainLibSectionSizesFromApk( | |
| 415 apk_filename, main_lib_info.filename) | |
| 416 for metric_name, size in main_lib_section_sizes.iteritems(): | |
| 417 ReportPerfResult(chartjson, apk_basename + '_MainLibInfo', | |
| 418 metric_name, size, 'bytes') | |
| 419 | |
| 368 # Main metric that we want to monitor for jumps. | 420 # Main metric that we want to monitor for jumps. |
| 369 normalized_apk_size = total_apk_size | 421 normalized_apk_size = total_apk_size |
| 370 # Always look at uncompressed .dex & .so. | 422 # Always look at uncompressed .dex & .so. |
| 371 normalized_apk_size -= java_code.ComputeZippedSize() | 423 normalized_apk_size -= java_code.ComputeZippedSize() |
| 372 normalized_apk_size += java_code.ComputeUncompressedSize() | 424 normalized_apk_size += java_code.ComputeUncompressedSize() |
| 373 normalized_apk_size -= native_code.ComputeZippedSize() | 425 normalized_apk_size -= native_code.ComputeZippedSize() |
| 374 normalized_apk_size += native_code.ComputeUncompressedSize() | 426 normalized_apk_size += native_code.ComputeUncompressedSize() |
| 375 # Avoid noise caused when strings change and translations haven't yet been | 427 # Avoid noise caused when strings change and translations haven't yet been |
| 376 # updated. | 428 # updated. |
| 377 english_pak = translations.FindByPattern(r'.*/en[-_][Uu][Ss]\.l?pak') | 429 english_pak = translations.FindByPattern(r'.*/en[-_][Uu][Ss]\.l?pak') |
| (...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 657 | 709 |
| 658 if chartjson: | 710 if chartjson: |
| 659 results_path = os.path.join(options.output_dir, 'results-chart.json') | 711 results_path = os.path.join(options.output_dir, 'results-chart.json') |
| 660 logging.critical('Dumping json to %s', results_path) | 712 logging.critical('Dumping json to %s', results_path) |
| 661 with open(results_path, 'w') as json_file: | 713 with open(results_path, 'w') as json_file: |
| 662 json.dump(chartjson, json_file) | 714 json.dump(chartjson, json_file) |
| 663 | 715 |
| 664 | 716 |
| 665 if __name__ == '__main__': | 717 if __name__ == '__main__': |
| 666 sys.exit(main(sys.argv)) | 718 sys.exit(main(sys.argv)) |
| OLD | NEW |