Chromium Code Reviews| Index: build/android/resource_sizes.py |
| diff --git a/build/android/resource_sizes.py b/build/android/resource_sizes.py |
| index 9877cdf8056a6fcfadbfde4980a2d87c5371d517..6c3653cb18c3651f8408fc6e0a72ff867b8e0740 100755 |
| --- a/build/android/resource_sizes.py |
| +++ b/build/android/resource_sizes.py |
| @@ -16,6 +16,7 @@ import operator |
| import optparse |
| import os |
| import re |
| +import shutil |
| import struct |
| import sys |
| import tempfile |
| @@ -99,20 +100,51 @@ _DUMP_STATIC_INITIALIZERS_PATH = os.path.join( |
| # Pragma exists when enable_resource_whitelist_generation=true. |
| _RC_HEADER_RE = re.compile( |
| r'^#define (?P<name>\w+) (?:_Pragma\(.*?\) )?(?P<id>\d+)$') |
| +_READELF_SIZES_METRICS = { |
| + 'text': ['text'], |
| + 'data': ['data', 'rodata'], |
| + 'relocations': ['rel.dyn', 'rel.plt', 'data.rel.ro', 'data.rel.ro.loca'], |
| + 'unwind': ['ARM.extab', 'ARM.exidx'], |
| + 'symbols': ['dynsym', 'dynstr', 'dynamic', 'shstrtab', 'got', 'plt'], |
| + 'other': ['hash', 'init_array', 'fini_array', 'comment', |
|
agrieve
2017/02/02 19:45:41
I don't think the list of sections is guaranteed t
estevenson
2017/02/02 21:34:54
True! I actually meant to do something like that b
|
| + 'note.gnu.gold-ve', 'ARM.attributes', 'note.gnu.build-i', |
| + 'gnu.version', 'gnu.version_d', 'gnu.version_r'] |
| +} |
| + |
| + |
| +def _ParseReadElfSectionSize(readelf_stdout, section_name): |
| + # Matches: .|section_name| Type Addr Off Size ES Flg Lk Inf Al |
| + match = re.search( |
| + r'\.%s\s+.*$' % re.escape(section_name), readelf_stdout, re.MULTILINE) |
| + return int(match.group(0).split()[4], 16) if match else None |
| + |
| + |
| +def _ExtractMainLibSectionSizesFromApk(apk_path, main_lib_path): |
| + tmpdir = tempfile.mkdtemp(suffix='_apk_extract') |
| + try: |
| + with zipfile.ZipFile(apk_path, 'r') as z: |
| + extracted_lib_path = z.extract(main_lib_path, tmpdir) |
| + return _ComputeMainLibSectionSizes(extracted_lib_path) |
| + finally: |
| + shutil.rmtree(tmpdir) |
| + |
| + |
| +def _ComputeMainLibSectionSizes(so_path): |
| + stdout = cmd_helper.GetCmdOutput(['readelf', '-S', so_path]) |
| + sizes = collections.defaultdict(int) |
| + for metric, section_names in _READELF_SIZES_METRICS.iteritems(): |
| + for section_name in section_names: |
| + section_size = _ParseReadElfSectionSize(stdout, section_name) |
| + if section_size: |
| + sizes[metric] += section_size |
| + |
| + return sizes |
| 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 |
| # (i.e. Clang is not supported currently). |
| - def get_elf_section_size(readelf_stdout, section_name): |
| - # Matches: .ctors PROGBITS 000000000516add0 5169dd0 000010 00 WA 0 0 8 |
| - match = re.search(r'\.%s.*$' % re.escape(section_name), |
| - readelf_stdout, re.MULTILINE) |
| - if not match: |
| - return (False, -1) |
| - size_str = re.split(r'\W+', match.group(0))[5] |
| - return (True, int(size_str, 16)) |
| # Find the number of files with at least one static initializer. |
| # First determine if we're 32 or 64 bit |
| @@ -129,8 +161,8 @@ def CountStaticInitializers(so_path): |
| # about how compiler and linker implement global static initializers. |
| si_count = 0 |
| stdout = cmd_helper.GetCmdOutput(['readelf', '-SW', so_path]) |
| - has_init_array, init_array_size = get_elf_section_size(stdout, 'init_array') |
| - if has_init_array: |
| + init_array_size = _ParseReadElfSectionSize(stdout, 'init_array') |
| + if init_array_size: |
| si_count = init_array_size / word_size |
| si_count = max(si_count, 0) |
| return si_count |
| @@ -365,6 +397,12 @@ def PrintApkAnalysis(apk_filename, chartjson=None): |
| ReportPerfResult(chartjson, apk_basename + '_Specifics', |
| 'other lib size', secondary_size, 'bytes') |
| + main_lib_section_sizes = _ExtractMainLibSectionSizesFromApk( |
| + apk_filename, main_lib_info.filename) |
| + for metric_name, size in main_lib_section_sizes.iteritems(): |
| + ReportPerfResult(chartjson, apk_basename + '_MainLibInfo', |
| + metric_name, size, 'bytes') |
| + |
| # Main metric that we want to monitor for jumps. |
| normalized_apk_size = total_apk_size |
| # Always look at uncompressed .dex & .so. |