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

Side by Side Diff: build/android/resource_sizes.py

Issue 2675703003: Add main lib section sizes to resource_sizes.py. (Closed)
Patch Set: Add comment for regex Created 3 years, 10 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 | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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_SIZES_METRICS = {
104 'text': ['text'],
105 'data': ['data', 'rodata'],
106 'relocations': ['rel.dyn', 'rel.plt', 'data.rel.ro', 'data.rel.ro.loca'],
107 'unwind': ['ARM.extab', 'ARM.exidx'],
108 'symbols': ['dynsym', 'dynstr', 'dynamic', 'shstrtab', 'got', 'plt'],
109 '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
110 'note.gnu.gold-ve', 'ARM.attributes', 'note.gnu.build-i',
111 'gnu.version', 'gnu.version_d', 'gnu.version_r']
112 }
113
114
115 def _ParseReadElfSectionSize(readelf_stdout, section_name):
116 # Matches: .|section_name| Type Addr Off Size ES Flg Lk Inf Al
117 match = re.search(
118 r'\.%s\s+.*$' % re.escape(section_name), readelf_stdout, re.MULTILINE)
119 return int(match.group(0).split()[4], 16) if match else None
120
121
122 def _ExtractMainLibSectionSizesFromApk(apk_path, main_lib_path):
123 tmpdir = tempfile.mkdtemp(suffix='_apk_extract')
124 try:
125 with zipfile.ZipFile(apk_path, 'r') as z:
126 extracted_lib_path = z.extract(main_lib_path, tmpdir)
127 return _ComputeMainLibSectionSizes(extracted_lib_path)
128 finally:
129 shutil.rmtree(tmpdir)
130
131
132 def _ComputeMainLibSectionSizes(so_path):
133 stdout = cmd_helper.GetCmdOutput(['readelf', '-S', so_path])
134 sizes = collections.defaultdict(int)
135 for metric, section_names in _READELF_SIZES_METRICS.iteritems():
136 for section_name in section_names:
137 section_size = _ParseReadElfSectionSize(stdout, section_name)
138 if section_size:
139 sizes[metric] += section_size
140
141 return sizes
102 142
103 143
104 def CountStaticInitializers(so_path): 144 def CountStaticInitializers(so_path):
105 # Static initializers expected in official builds. Note that this list is 145 # 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 146 # built using 'nm' on libchrome.so which results from a GCC official build
107 # (i.e. Clang is not supported currently). 147 # (i.e. Clang is not supported currently).
108 def get_elf_section_size(readelf_stdout, section_name):
109 # Matches: .ctors PROGBITS 000000000516add0 5169dd0 000010 00 WA 0 0 8
110 match = re.search(r'\.%s.*$' % re.escape(section_name),
111 readelf_stdout, re.MULTILINE)
112 if not match:
113 return (False, -1)
114 size_str = re.split(r'\W+', match.group(0))[5]
115 return (True, int(size_str, 16))
116 148
117 # Find the number of files with at least one static initializer. 149 # Find the number of files with at least one static initializer.
118 # First determine if we're 32 or 64 bit 150 # First determine if we're 32 or 64 bit
119 stdout = cmd_helper.GetCmdOutput(['readelf', '-h', so_path]) 151 stdout = cmd_helper.GetCmdOutput(['readelf', '-h', so_path])
120 elf_class_line = re.search('Class:.*$', stdout, re.MULTILINE).group(0) 152 elf_class_line = re.search('Class:.*$', stdout, re.MULTILINE).group(0)
121 elf_class = re.split(r'\W+', elf_class_line)[1] 153 elf_class = re.split(r'\W+', elf_class_line)[1]
122 if elf_class == 'ELF32': 154 if elf_class == 'ELF32':
123 word_size = 4 155 word_size = 4
124 else: 156 else:
125 word_size = 8 157 word_size = 8
126 158
127 # Then find the number of files with global static initializers. 159 # Then find the number of files with global static initializers.
128 # NOTE: this is very implementation-specific and makes assumptions 160 # NOTE: this is very implementation-specific and makes assumptions
129 # about how compiler and linker implement global static initializers. 161 # about how compiler and linker implement global static initializers.
130 si_count = 0 162 si_count = 0
131 stdout = cmd_helper.GetCmdOutput(['readelf', '-SW', so_path]) 163 stdout = cmd_helper.GetCmdOutput(['readelf', '-SW', so_path])
132 has_init_array, init_array_size = get_elf_section_size(stdout, 'init_array') 164 init_array_size = _ParseReadElfSectionSize(stdout, 'init_array')
133 if has_init_array: 165 if init_array_size:
134 si_count = init_array_size / word_size 166 si_count = init_array_size / word_size
135 si_count = max(si_count, 0) 167 si_count = max(si_count, 0)
136 return si_count 168 return si_count
137 169
138 170
139 def GetStaticInitializers(so_path): 171 def GetStaticInitializers(so_path):
140 output = cmd_helper.GetCmdOutput([_DUMP_STATIC_INITIALIZERS_PATH, '-d', 172 output = cmd_helper.GetCmdOutput([_DUMP_STATIC_INITIALIZERS_PATH, '-d',
141 so_path]) 173 so_path])
142 return output.splitlines() 174 return output.splitlines()
143 175
(...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after
358 # Size of main .so vs remaining. 390 # Size of main .so vs remaining.
359 main_lib_info = native_code.FindLargest() 391 main_lib_info = native_code.FindLargest()
360 if main_lib_info: 392 if main_lib_info:
361 main_lib_size = main_lib_info.file_size 393 main_lib_size = main_lib_info.file_size
362 ReportPerfResult(chartjson, apk_basename + '_Specifics', 394 ReportPerfResult(chartjson, apk_basename + '_Specifics',
363 'main lib size', main_lib_size, 'bytes') 395 'main lib size', main_lib_size, 'bytes')
364 secondary_size = native_code.ComputeUncompressedSize() - main_lib_size 396 secondary_size = native_code.ComputeUncompressedSize() - main_lib_size
365 ReportPerfResult(chartjson, apk_basename + '_Specifics', 397 ReportPerfResult(chartjson, apk_basename + '_Specifics',
366 'other lib size', secondary_size, 'bytes') 398 'other lib size', secondary_size, 'bytes')
367 399
400 main_lib_section_sizes = _ExtractMainLibSectionSizesFromApk(
401 apk_filename, main_lib_info.filename)
402 for metric_name, size in main_lib_section_sizes.iteritems():
403 ReportPerfResult(chartjson, apk_basename + '_MainLibInfo',
404 metric_name, size, 'bytes')
405
368 # Main metric that we want to monitor for jumps. 406 # Main metric that we want to monitor for jumps.
369 normalized_apk_size = total_apk_size 407 normalized_apk_size = total_apk_size
370 # Always look at uncompressed .dex & .so. 408 # Always look at uncompressed .dex & .so.
371 normalized_apk_size -= java_code.ComputeZippedSize() 409 normalized_apk_size -= java_code.ComputeZippedSize()
372 normalized_apk_size += java_code.ComputeUncompressedSize() 410 normalized_apk_size += java_code.ComputeUncompressedSize()
373 normalized_apk_size -= native_code.ComputeZippedSize() 411 normalized_apk_size -= native_code.ComputeZippedSize()
374 normalized_apk_size += native_code.ComputeUncompressedSize() 412 normalized_apk_size += native_code.ComputeUncompressedSize()
375 # Avoid noise caused when strings change and translations haven't yet been 413 # Avoid noise caused when strings change and translations haven't yet been
376 # updated. 414 # updated.
377 english_pak = translations.FindByPattern(r'.*/en[-_][Uu][Ss]\.l?pak') 415 english_pak = translations.FindByPattern(r'.*/en[-_][Uu][Ss]\.l?pak')
(...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after
657 695
658 if chartjson: 696 if chartjson:
659 results_path = os.path.join(options.output_dir, 'results-chart.json') 697 results_path = os.path.join(options.output_dir, 'results-chart.json')
660 logging.critical('Dumping json to %s', results_path) 698 logging.critical('Dumping json to %s', results_path)
661 with open(results_path, 'w') as json_file: 699 with open(results_path, 'w') as json_file:
662 json.dump(chartjson, json_file) 700 json.dump(chartjson, json_file)
663 701
664 702
665 if __name__ == '__main__': 703 if __name__ == '__main__':
666 sys.exit(main(sys.argv)) 704 sys.exit(main(sys.argv))
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698