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 |
66 _RC_HEADER_RE = re.compile(r'^#define (?P<name>\w+) (?P<id>\d+)$') | 48 _RC_HEADER_RE = re.compile(r'^#define (?P<name>\w+) (?P<id>\d+)$') |
67 | 49 |
68 | 50 |
51 def CountStaticInitializers(so_path): | |
52 def get_elf_section_size(readelf_stdout, section_name): | |
53 # Matches: .ctors PROGBITS 000000000516add0 5169dd0 000010 00 WA 0 0 8 | |
54 match = re.search(r'\.%s.*$' % re.escape(section_name), | |
55 readelf_stdout, re.MULTILINE) | |
56 if not match: | |
57 return (False, -1) | |
58 size_str = re.split(r'\W+', match.group(0))[5] | |
59 return (True, int(size_str, 16)) | |
60 | |
61 # Find the number of files with at least one static initializer. | |
62 # First determine if we're 32 or 64 bit | |
63 stdout = cmd_helper.GetCmdOutput(['readelf', '-h', so_path]) | |
64 elf_class_line = re.search('Class:.*$', stdout, re.MULTILINE).group(0) | |
65 elf_class = re.split(r'\W+', elf_class_line)[1] | |
66 if elf_class == 'ELF32': | |
67 word_size = 4 | |
68 else: | |
69 word_size = 8 | |
70 | |
71 # Then find the number of files with global static initializers. | |
72 # NOTE: this is very implementation-specific and makes assumptions | |
73 # about how compiler and linker implement global static initializers. | |
74 si_count = 0 | |
75 stdout = cmd_helper.GetCmdOutput(['readelf', '-SW', so_path]) | |
76 has_init_array, init_array_size = get_elf_section_size(stdout, 'init_array') | |
77 if has_init_array: | |
78 si_count = init_array_size / word_size | |
79 si_count = max(si_count, 0) | |
80 return si_count | |
81 | |
82 | |
69 def GetStaticInitializers(so_path): | 83 def GetStaticInitializers(so_path): |
70 """Returns a list of static initializers found in the non-stripped library | 84 dump_initializers = os.path.join(host_paths.DIR_SOURCE_ROOT, 'tools', 'linux', |
perezju
2016/02/01 10:23:59
nit: maybe this can be a module-level constant?
rnephew (Reviews Here)
2016/02/01 15:46:19
Done.
| |
71 located at the provided path. Note that this function assumes that the | 85 'dump-static-initializers.py') |
72 library was compiled with GCC. | 86 output = cmd_helper.GetCmdOutput([dump_initializers, '-d', so_path]) |
73 """ | 87 return output.splitlines() |
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 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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 print 'Files with static initializers:' |
317 si_count = CountStaticInitializers(so_with_symbols_path) | |
311 static_initializers = GetStaticInitializers(so_with_symbols_path) | 318 static_initializers = GetStaticInitializers(so_with_symbols_path) |
perezju
2016/02/01 10:23:59
Asking mostly out of ignorance, but could si_count
rnephew (Reviews Here)
2016/02/01 15:46:19
https://codereview.chromium.org/1445633002/
perezju
2016/02/03 11:09:02
I had a look but I'm still confused:
1. is si_cou
| |
312 print '\n'.join(static_initializers) | 319 print '\n'.join(static_initializers) |
313 | 320 |
314 ReportPerfResult(chartjson, 'StaticInitializersCount', 'count', | 321 ReportPerfResult(chartjson, 'StaticInitializersCount', 'count', |
315 len(static_initializers), 'count') | 322 si_count, 'count') |
316 | |
317 | 323 |
318 def _FormatBytes(byts): | 324 def _FormatBytes(byts): |
319 """Pretty-print a number of bytes.""" | 325 """Pretty-print a number of bytes.""" |
320 if byts > 2**20.0: | 326 if byts > 2**20.0: |
321 byts /= 2**20.0 | 327 byts /= 2**20.0 |
322 return '%.2fm' % byts | 328 return '%.2fm' % byts |
323 if byts > 2**10.0: | 329 if byts > 2**10.0: |
324 byts /= 2**10.0 | 330 byts /= 2**10.0 |
325 return '%.2fk' % byts | 331 return '%.2fk' % byts |
326 return str(byts) | 332 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) | 390 PrintPakAnalysis(f, options.min_pak_resource_size, options.build_type) |
385 | 391 |
386 if chartjson: | 392 if chartjson: |
387 results_path = os.path.join(options.outpur_dir, 'results-chart.json') | 393 results_path = os.path.join(options.outpur_dir, 'results-chart.json') |
388 with open(results_path, 'w') as json_file: | 394 with open(results_path, 'w') as json_file: |
389 json.dump(chartjson, json_file) | 395 json.dump(chartjson, json_file) |
390 | 396 |
391 | 397 |
392 if __name__ == '__main__': | 398 if __name__ == '__main__': |
393 sys.exit(main(sys.argv)) | 399 sys.exit(main(sys.argv)) |
OLD | NEW |