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

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

Issue 2244653003: 🚀 Add dex info and static initializers to resource_sizes.py (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add dex info and static initializers to resource_sizes.py Created 4 years, 4 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 | « build/android/method_count.py ('k') | 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 struct 19 import struct
20 import sys 20 import sys
21 import tempfile 21 import tempfile
22 import zipfile 22 import zipfile
23 import zlib 23 import zlib
24 24
25 import devil_chromium 25 import devil_chromium
26 from devil.utils import cmd_helper 26 from devil.utils import cmd_helper
27 import method_count
27 from pylib import constants 28 from pylib import constants
28 from pylib.constants import host_paths 29 from pylib.constants import host_paths
29 30
30 _GRIT_PATH = os.path.join(host_paths.DIR_SOURCE_ROOT, 'tools', 'grit') 31 _GRIT_PATH = os.path.join(host_paths.DIR_SOURCE_ROOT, 'tools', 'grit')
31 32
32 # Prepend the grit module from the source tree so it takes precedence over other 33 # Prepend the grit module from the source tree so it takes precedence over other
33 # grit versions that might present in the search path. 34 # grit versions that might present in the search path.
34 with host_paths.SysPath(_GRIT_PATH, 1): 35 with host_paths.SysPath(_GRIT_PATH, 1):
35 from grit.format import data_pack # pylint: disable=import-error 36 from grit.format import data_pack # pylint: disable=import-error
36 37
37 with host_paths.SysPath(host_paths.BUILD_COMMON_PATH): 38 with host_paths.SysPath(host_paths.BUILD_COMMON_PATH):
38 import perf_tests_results_helper # pylint: disable=import-error 39 import perf_tests_results_helper # pylint: disable=import-error
39 40
41
40 # Python had a bug in zipinfo parsing that triggers on ChromeModern.apk 42 # Python had a bug in zipinfo parsing that triggers on ChromeModern.apk
41 # https://bugs.python.org/issue14315 43 # https://bugs.python.org/issue14315
42 def _PatchedDecodeExtra(self): 44 def _PatchedDecodeExtra(self):
43 # Try to decode the extra field. 45 # Try to decode the extra field.
44 extra = self.extra 46 extra = self.extra
45 unpack = struct.unpack 47 unpack = struct.unpack
46 while len(extra) >= 4: 48 while len(extra) >= 4:
47 tp, ln = unpack('<HH', extra[:4]) 49 tp, ln = unpack('<HH', extra[:4])
48 if tp == 1: 50 if tp == 1:
49 if ln >= 24: 51 if ln >= 24:
(...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after
347 if m: 349 if m:
348 i = int(m.group('id')) 350 i = int(m.group('id'))
349 name = m.group('name') 351 name = m.group('name')
350 if i in id_name_map and name != id_name_map[i]: 352 if i in id_name_map and name != id_name_map[i]:
351 print 'WARNING: Resource ID conflict %s (%s vs %s)' % ( 353 print 'WARNING: Resource ID conflict %s (%s vs %s)' % (
352 i, id_name_map[i], name) 354 i, id_name_map[i], name)
353 id_name_map[i] = name 355 id_name_map[i] = name
354 return id_name_map 356 return id_name_map
355 357
356 358
357 def PrintStaticInitializersCount(so_with_symbols_path, chartjson=None): 359 def _PrintStaticInitializersCountFromApk(apk_filename, chartjson=None):
358 """Emits the performance result for static initializers found in the provided 360 print 'Finding static initializers (can take a minute)'
359 shared library. Additionally, files for which static initializers were 361 with zipfile.ZipFile(apk_filename) as z:
360 found are printed on the standard output. 362 namelist = z.namelist()
363 out_dir = constants.GetOutDirectory()
364 si_count = 0
365 for subpath in namelist:
366 if subpath.endswith('.so'):
367 unstripped_path = os.path.join(out_dir, 'lib.unstripped',
368 os.path.basename(subpath))
369 if os.path.exists(unstripped_path):
370 si_count += _PrintStaticInitializersCount(unstripped_path)
371 else:
372 raise Exception('Unstripped .so not found. Looked here: %s',
373 unstripped_path)
374 ReportPerfResult(chartjson, 'StaticInitializersCount', 'count', si_count,
375 'count')
376
377
378 def _PrintStaticInitializersCount(so_with_symbols_path):
379 """Counts the number of static initializers in the given shared library.
380 Additionally, files for which static initializers were found are printed
381 on the standard output.
361 382
362 Args: 383 Args:
363 so_with_symbols_path: Path to the unstripped libchrome.so file. 384 so_with_symbols_path: Path to the unstripped libchrome.so file.
385
386 Returns:
387 The number of static initializers found.
364 """ 388 """
365 # GetStaticInitializers uses get-static-initializers.py to get a list of all 389 # GetStaticInitializers uses get-static-initializers.py to get a list of all
366 # static initializers. This does not work on all archs (particularly arm). 390 # static initializers. This does not work on all archs (particularly arm).
367 # TODO(rnephew): Get rid of warning when crbug.com/585588 is fixed. 391 # TODO(rnephew): Get rid of warning when crbug.com/585588 is fixed.
368 si_count = CountStaticInitializers(so_with_symbols_path) 392 si_count = CountStaticInitializers(so_with_symbols_path)
369 static_initializers = GetStaticInitializers(so_with_symbols_path) 393 static_initializers = GetStaticInitializers(so_with_symbols_path)
370 if si_count != len(static_initializers): 394 static_initializers_count = len(static_initializers) - 1 # Minus summary.
395 if si_count != static_initializers_count:
371 print ('There are %d files with static initializers, but ' 396 print ('There are %d files with static initializers, but '
372 'dump-static-initializers found %d:' % 397 'dump-static-initializers found %d:' %
373 (si_count, len(static_initializers))) 398 (si_count, static_initializers_count))
374 else: 399 else:
375 print 'Found %d files with static initializers:' % si_count 400 print '%s - Found %d files with static initializers:' % (
401 os.path.basename(so_with_symbols_path), si_count)
376 print '\n'.join(static_initializers) 402 print '\n'.join(static_initializers)
377 403
378 ReportPerfResult(chartjson, 'StaticInitializersCount', 'count', 404 return si_count
379 si_count, 'count')
380 405
381 def _FormatBytes(byts): 406 def _FormatBytes(byts):
382 """Pretty-print a number of bytes.""" 407 """Pretty-print a number of bytes."""
383 if byts > 2**20.0: 408 if byts > 2**20.0:
384 byts /= 2**20.0 409 byts /= 2**20.0
385 return '%.2fm' % byts 410 return '%.2fm' % byts
386 if byts > 2**10.0: 411 if byts > 2**10.0:
387 byts /= 2**10.0 412 byts /= 2**10.0
388 return '%.2fk' % byts 413 return '%.2fk' % byts
389 return str(byts) 414 return str(byts)
390 415
391 416
392 def _CalculateCompressedSize(file_path): 417 def _CalculateCompressedSize(file_path):
393 CHUNK_SIZE = 256 * 1024 418 CHUNK_SIZE = 256 * 1024
394 compressor = zlib.compressobj() 419 compressor = zlib.compressobj()
395 total_size = 0 420 total_size = 0
396 with open(file_path, 'rb') as f: 421 with open(file_path, 'rb') as f:
397 for chunk in iter(lambda: f.read(CHUNK_SIZE), ''): 422 for chunk in iter(lambda: f.read(CHUNK_SIZE), ''):
398 total_size += len(compressor.compress(chunk)) 423 total_size += len(compressor.compress(chunk))
399 total_size += len(compressor.flush()) 424 total_size += len(compressor.flush())
400 return total_size 425 return total_size
401 426
402 427
428 def _PrintDexAnalysis(apk_filename, chartjson=None):
429 sizes = method_count.ExtractSizesFromZip(apk_filename)
430
431 graph_title = os.path.basename(apk_filename) + '_Dex'
432 dex_metrics = method_count.CONTRIBUTORS_TO_DEX_CACHE
433 for key, label in dex_metrics.iteritems():
434 ReportPerfResult(chartjson, graph_title, label, sizes[key], 'entries')
435
436 graph_title = '%sCache' % graph_title
437 ReportPerfResult(chartjson, graph_title, 'DexCache', sizes['dex_cache_size'],
438 'bytes')
439
440
403 def main(argv): 441 def main(argv):
404 usage = """Usage: %prog [options] file1 file2 ... 442 usage = """Usage: %prog [options] file1 file2 ...
405 443
406 Pass any number of files to graph their sizes. Any files with the extension 444 Pass any number of files to graph their sizes. Any files with the extension
407 '.apk' will be broken down into their components on a separate graph.""" 445 '.apk' will be broken down into their components on a separate graph."""
408 option_parser = optparse.OptionParser(usage=usage) 446 option_parser = optparse.OptionParser(usage=usage)
409 option_parser.add_option('--so-path', help='Path to libchrome.so.') 447 option_parser.add_option('--so-path', help='Path to libchrome.so.')
410 option_parser.add_option('--so-with-symbols-path', 448 option_parser.add_option('--so-with-symbols-path',
411 help='Path to libchrome.so with symbols.') 449 help='Path to libchrome.so with symbols.')
412 option_parser.add_option('--min-pak-resource-size', type='int', 450 option_parser.add_option('--min-pak-resource-size', type='int',
(...skipping 24 matching lines...) Expand all
437 # more. 475 # more.
438 if options.so_path: 476 if options.so_path:
439 files.append(options.so_path) 477 files.append(options.so_path)
440 478
441 if not files: 479 if not files:
442 option_parser.error('Must specify a file') 480 option_parser.error('Must specify a file')
443 481
444 devil_chromium.Initialize() 482 devil_chromium.Initialize()
445 483
446 if options.so_with_symbols_path: 484 if options.so_with_symbols_path:
447 PrintStaticInitializersCount( 485 si_count = _PrintStaticInitializersCount(options.so_with_symbols_path)
448 options.so_with_symbols_path, chartjson=chartjson) 486 ReportPerfResult(chartjson, 'StaticInitializersCount', 'count', si_count,
487 'count')
449 488
450 PrintResourceSizes(files, chartjson=chartjson) 489 PrintResourceSizes(files, chartjson=chartjson)
451 490
452 for f in files: 491 for f in files:
453 if f.endswith('.apk'): 492 if f.endswith('.apk'):
454 PrintApkAnalysis(f, chartjson=chartjson) 493 PrintApkAnalysis(f, chartjson=chartjson)
455 PrintPakAnalysis(f, options.min_pak_resource_size) 494 PrintPakAnalysis(f, options.min_pak_resource_size)
495 _PrintDexAnalysis(f, chartjson=chartjson)
496 if not options.so_with_symbols_path:
497 _PrintStaticInitializersCountFromApk(f, chartjson=chartjson)
456 498
457 if chartjson: 499 if chartjson:
458 results_path = os.path.join(options.output_dir, 'results-chart.json') 500 results_path = os.path.join(options.output_dir, 'results-chart.json')
459 logging.critical('Dumping json to %s', results_path) 501 logging.critical('Dumping json to %s', results_path)
460 with open(results_path, 'w') as json_file: 502 with open(results_path, 'w') as json_file:
461 json.dump(chartjson, json_file) 503 json.dump(chartjson, json_file)
462 504
463 505
464 if __name__ == '__main__': 506 if __name__ == '__main__':
465 sys.exit(main(sys.argv)) 507 sys.exit(main(sys.argv))
OLDNEW
« no previous file with comments | « build/android/method_count.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698