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 """ |
(...skipping 19 matching lines...) Expand all Loading... | |
30 from grit.format import data_pack # pylint: disable=import-error | 30 from grit.format import data_pack # pylint: disable=import-error |
31 | 31 |
32 with host_paths.SysPath(host_paths.BUILD_COMMON_PATH): | 32 with host_paths.SysPath(host_paths.BUILD_COMMON_PATH): |
33 import perf_tests_results_helper # pylint: disable=import-error | 33 import perf_tests_results_helper # pylint: disable=import-error |
34 | 34 |
35 | 35 |
36 # Static initializers expected in official builds. Note that this list is built | 36 # Static initializers expected in official builds. Note that this list is built |
37 # using 'nm' on libchrome.so which results from a GCC official build (i.e. | 37 # using 'nm' on libchrome.so which results from a GCC official build (i.e. |
38 # Clang is not supported currently). | 38 # Clang is not supported currently). |
39 | 39 |
40 STATIC_INITIALIZER_SYMBOL_PREFIX = '_GLOBAL__I_' | |
41 | |
42 EXPECTED_STATIC_INITIALIZERS = frozenset([ | |
43 'allocators.cpp', | |
44 'common.pb.cc', | |
45 'defaults.cc', | |
46 'generated_message_util.cc', | |
47 'locale_impl.cpp', | |
48 'timeutils.cc', | |
49 'watchdog.cc', | |
50 # http://b/6354040 | |
51 'SkFontHost_android.cpp', | |
52 # http://b/6354040 | |
53 'isolate.cc', | |
54 'assembler_arm.cc', | |
55 'isolate.cc', | |
56 ]) | |
57 | |
58 _BASE_CHART = { | 40 _BASE_CHART = { |
59 'format_version': '0.1', | 41 'format_version': '0.1', |
60 'benchmark_name': 'resource_sizes', | 42 'benchmark_name': 'resource_sizes', |
61 'benchmark_description': 'APK resource size information.', | 43 'benchmark_description': 'APK resource size information.', |
62 'trace_rerun_options': [], | 44 'trace_rerun_options': [], |
63 'charts': {} | 45 'charts': {} |
64 } | 46 } |
65 | 47 _DUMP_STATIC_INITIALIZERS_PATH = os.path.join( |
48 host_paths.DIR_SOURCE_ROOT, 'tools', 'linux', 'dump-static-initializers.py') | |
66 _RC_HEADER_RE = re.compile(r'^#define (?P<name>\w+) (?P<id>\d+)$') | 49 _RC_HEADER_RE = re.compile(r'^#define (?P<name>\w+) (?P<id>\d+)$') |
67 | 50 |
68 | 51 |
52 def CountStaticInitializers(so_path): | |
53 def get_elf_section_size(readelf_stdout, section_name): | |
54 # Matches: .ctors PROGBITS 000000000516add0 5169dd0 000010 00 WA 0 0 8 | |
55 match = re.search(r'\.%s.*$' % re.escape(section_name), | |
56 readelf_stdout, re.MULTILINE) | |
57 if not match: | |
58 return (False, -1) | |
59 size_str = re.split(r'\W+', match.group(0))[5] | |
60 return (True, int(size_str, 16)) | |
61 | |
62 # Find the number of files with at least one static initializer. | |
63 # First determine if we're 32 or 64 bit | |
64 stdout = cmd_helper.GetCmdOutput(['readelf', '-h', so_path]) | |
65 elf_class_line = re.search('Class:.*$', stdout, re.MULTILINE).group(0) | |
66 elf_class = re.split(r'\W+', elf_class_line)[1] | |
67 if elf_class == 'ELF32': | |
68 word_size = 4 | |
69 else: | |
70 word_size = 8 | |
71 | |
72 # Then find the number of files with global static initializers. | |
73 # NOTE: this is very implementation-specific and makes assumptions | |
74 # about how compiler and linker implement global static initializers. | |
75 si_count = 0 | |
76 stdout = cmd_helper.GetCmdOutput(['readelf', '-SW', so_path]) | |
77 has_init_array, init_array_size = get_elf_section_size(stdout, 'init_array') | |
78 if has_init_array: | |
79 si_count = init_array_size / word_size | |
80 si_count = max(si_count, 0) | |
81 return si_count | |
82 | |
83 | |
69 def GetStaticInitializers(so_path): | 84 def GetStaticInitializers(so_path): |
70 """Returns a list of static initializers found in the non-stripped library | 85 output = cmd_helper.GetCmdOutput([_DUMP_STATIC_INITIALIZERS_PATH, '-d', |
71 located at the provided path. Note that this function assumes that the | 86 so_path]) |
72 library was compiled with GCC. | 87 return output.splitlines() |
73 """ | |
74 output = cmd_helper.GetCmdOutput(['nm', so_path]) | |
75 static_initializers = [] | |
76 for line in output: | |
77 symbol_name = line.split(' ').pop().rstrip() | |
78 if STATIC_INITIALIZER_SYMBOL_PREFIX in symbol_name: | |
79 static_initializers.append( | |
80 symbol_name.replace(STATIC_INITIALIZER_SYMBOL_PREFIX, '')) | |
81 return static_initializers | |
82 | 88 |
83 | 89 |
84 def ReportPerfResult(chart_data, graph_title, trace_title, value, units, | 90 def ReportPerfResult(chart_data, graph_title, trace_title, value, units, |
85 improvement_direction='down', important=True): | 91 improvement_direction='down', important=True): |
86 """Outputs test results in correct format. | 92 """Outputs test results in correct format. |
87 | 93 |
88 If chart_data is None, it outputs data in old format. If chart_data is a | 94 If chart_data is None, it outputs data in old format. If chart_data is a |
89 dictionary, formats in chartjson format. If any other format defaults to | 95 dictionary, formats in chartjson format. If any other format defaults to |
90 old format. | 96 old format. |
91 """ | 97 """ |
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
300 | 306 |
301 | 307 |
302 def PrintStaticInitializersCount(so_with_symbols_path, chartjson=None): | 308 def PrintStaticInitializersCount(so_with_symbols_path, chartjson=None): |
303 """Emits the performance result for static initializers found in the provided | 309 """Emits the performance result for static initializers found in the provided |
304 shared library. Additionally, files for which static initializers were | 310 shared library. Additionally, files for which static initializers were |
305 found are printed on the standard output. | 311 found are printed on the standard output. |
306 | 312 |
307 Args: | 313 Args: |
308 so_with_symbols_path: Path to the unstripped libchrome.so file. | 314 so_with_symbols_path: Path to the unstripped libchrome.so file. |
309 """ | 315 """ |
310 print 'Files with static initializers:' | 316 # GetStaticInitializers uses get-static-initializers.py to get a list of all |
317 # static initializers. This does not work on all archs (particularly arm). | |
perezju
2016/02/10 09:56:17
nit: add a TODO with a link to the bug to get this
rnephew (Reviews Here)
2016/02/10 15:57:09
Done.
| |
318 si_count = CountStaticInitializers(so_with_symbols_path) | |
311 static_initializers = GetStaticInitializers(so_with_symbols_path) | 319 static_initializers = GetStaticInitializers(so_with_symbols_path) |
320 if si_count != len(static_initializers): | |
321 print ('Warning: Number of static intializers an files found with ' | |
322 'dump-static-initializers do not match.') | |
323 print '%s Files with static initializers:' % si_count | |
perezju
2016/02/10 09:56:17
nit: I would rephrase these as:
sizes match:
- '
rnephew (Reviews Here)
2016/02/10 15:57:09
Done.
| |
312 print '\n'.join(static_initializers) | 324 print '\n'.join(static_initializers) |
313 | 325 |
314 ReportPerfResult(chartjson, 'StaticInitializersCount', 'count', | 326 ReportPerfResult(chartjson, 'StaticInitializersCount', 'count', |
315 len(static_initializers), 'count') | 327 si_count, 'count') |
316 | |
317 | 328 |
318 def _FormatBytes(byts): | 329 def _FormatBytes(byts): |
319 """Pretty-print a number of bytes.""" | 330 """Pretty-print a number of bytes.""" |
320 if byts > 2**20.0: | 331 if byts > 2**20.0: |
321 byts /= 2**20.0 | 332 byts /= 2**20.0 |
322 return '%.2fm' % byts | 333 return '%.2fm' % byts |
323 if byts > 2**10.0: | 334 if byts > 2**10.0: |
324 byts /= 2**10.0 | 335 byts /= 2**10.0 |
325 return '%.2fk' % byts | 336 return '%.2fk' % byts |
326 return str(byts) | 337 return str(byts) |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
384 PrintPakAnalysis(f, options.min_pak_resource_size, options.build_type) | 395 PrintPakAnalysis(f, options.min_pak_resource_size, options.build_type) |
385 | 396 |
386 if chartjson: | 397 if chartjson: |
387 results_path = os.path.join(options.outpur_dir, 'results-chart.json') | 398 results_path = os.path.join(options.outpur_dir, 'results-chart.json') |
388 with open(results_path, 'w') as json_file: | 399 with open(results_path, 'w') as json_file: |
389 json.dump(chartjson, json_file) | 400 json.dump(chartjson, json_file) |
390 | 401 |
391 | 402 |
392 if __name__ == '__main__': | 403 if __name__ == '__main__': |
393 sys.exit(main(sys.argv)) | 404 sys.exit(main(sys.argv)) |
OLD | NEW |