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

Side by Side Diff: tools/binary_size/diagnose_bloat.py

Issue 2871143004: diagnose_bloat.py: swap --silent with --verbose. (Closed)
Patch Set: Add IsAndroid to enable_chrome_android_internal Created 3 years, 7 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 | « tools/binary_size/README.md ('k') | tools/binary_size/libsupersize/describe.py » ('j') | 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/env python 1 #!/usr/bin/env python
2 # Copyright 2017 The Chromium Authors. All rights reserved. 2 # Copyright 2017 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 """Tool for finding the cause of APK bloat. 6 """Tool for finding the cause of binary size bloat.
7 7
8 Run diagnose_apk_bloat.py -h for detailed usage help. 8 See //tools/binary_size/README.md for example usage.
9
10 Note: this tool will perform gclient sync/git checkout on your local repo if
11 you don't use the --cloud option.
9 """ 12 """
10 13
11 import atexit 14 import atexit
12 import argparse 15 import argparse
13 import collections 16 import collections
14 from contextlib import contextmanager 17 from contextlib import contextmanager
15 import distutils.spawn 18 import distutils.spawn
16 import json 19 import json
17 import logging 20 import logging
18 import multiprocessing 21 import multiprocessing
19 import os 22 import os
20 import re 23 import re
21 import shutil 24 import shutil
22 import subprocess 25 import subprocess
23 import sys 26 import sys
24 import tempfile 27 import tempfile
25 import zipfile 28 import zipfile
26 29
27 _COMMIT_COUNT_WARN_THRESHOLD = 15 30 _COMMIT_COUNT_WARN_THRESHOLD = 15
28 _ALLOWED_CONSECUTIVE_FAILURES = 2 31 _ALLOWED_CONSECUTIVE_FAILURES = 2
29 _DIFF_DETAILS_LINES_THRESHOLD = 100 32 _DIFF_DETAILS_LINES_THRESHOLD = 100
30 _BUILDER_URL = \
31 'https://build.chromium.org/p/chromium.perf/builders/Android%20Builder'
32 _SRC_ROOT = os.path.abspath( 33 _SRC_ROOT = os.path.abspath(
33 os.path.join(os.path.dirname(__file__), os.pardir, os.pardir)) 34 os.path.join(os.path.dirname(__file__), os.pardir, os.pardir))
34 _DEFAULT_ARCHIVE_DIR = os.path.join(_SRC_ROOT, 'binary-size-bloat') 35 _DEFAULT_ARCHIVE_DIR = os.path.join(_SRC_ROOT, 'binary-size-bloat')
35 _DEFAULT_OUT_DIR = os.path.join(_SRC_ROOT, 'out', 'diagnose-apk-bloat') 36 _DEFAULT_OUT_DIR = os.path.join(_SRC_ROOT, 'out', 'diagnose-apk-bloat')
36 _DEFAULT_ANDROID_TARGET = 'monochrome_public_apk' 37 _DEFAULT_ANDROID_TARGET = 'monochrome_public_apk'
37 38
38 39
39 _DiffResult = collections.namedtuple('DiffResult', ['name', 'value', 'units']) 40 _DiffResult = collections.namedtuple('DiffResult', ['name', 'value', 'units'])
40 41
41 42
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after
207 elif 'monochrome' in self.target: 208 elif 'monochrome' in self.target:
208 return 'lib.unstripped/libmonochrome.so' 209 return 'lib.unstripped/libmonochrome.so'
209 else: 210 else:
210 return 'lib.unstripped/libchrome.so' 211 return 'lib.unstripped/libchrome.so'
211 212
212 @property 213 @property
213 def abs_main_lib_path(self): 214 def abs_main_lib_path(self):
214 return os.path.join(self.output_directory, self.main_lib_path) 215 return os.path.join(self.output_directory, self.main_lib_path)
215 216
216 @property 217 @property
218 def builder_url(self):
219 url = 'https://build.chromium.org/p/chromium.perf/builders/%s%%20Builder'
220 return url % self.target_os.title()
221
222 @property
217 def download_bucket(self): 223 def download_bucket(self):
218 return 'gs://chrome-perf/%s Builder/' % self.target_os.title() 224 return 'gs://chrome-perf/%s Builder/' % self.target_os.title()
219 225
220 @property 226 @property
221 def download_output_dir(self): 227 def download_output_dir(self):
222 return 'out/Release' if self.IsAndroid() else 'full-build-linux' 228 return 'out/Release' if self.IsAndroid() else 'full-build-linux'
223 229
224 @property 230 @property
225 def map_file_path(self): 231 def map_file_path(self):
226 return self.main_lib_path + '.map.gz' 232 return self.main_lib_path + '.map.gz'
(...skipping 14 matching lines...) Expand all
241 self.extra_gn_args_str = ' is_chrome_branded=true' 247 self.extra_gn_args_str = ' is_chrome_branded=true'
242 else: 248 else:
243 self.extra_gn_args_str = (' exclude_unwind_tables=true ' 249 self.extra_gn_args_str = (' exclude_unwind_tables=true '
244 'ffmpeg_branding="Chrome" proprietary_codecs=true') 250 'ffmpeg_branding="Chrome" proprietary_codecs=true')
245 self.target = self.target if self.IsAndroid() else 'chrome' 251 self.target = self.target if self.IsAndroid() else 'chrome'
246 252
247 def _GenGnCmd(self): 253 def _GenGnCmd(self):
248 gn_args = 'is_official_build=true symbol_level=1' 254 gn_args = 'is_official_build=true symbol_level=1'
249 gn_args += ' use_goma=%s' % str(self.use_goma).lower() 255 gn_args += ' use_goma=%s' % str(self.use_goma).lower()
250 gn_args += ' target_os="%s"' % self.target_os 256 gn_args += ' target_os="%s"' % self.target_os
251 gn_args += (' enable_chrome_android_internal=%s' % 257 if self.IsAndroid():
252 str(self.enable_chrome_android_internal).lower()) 258 gn_args += (' enable_chrome_android_internal=%s' %
259 str(self.enable_chrome_android_internal).lower())
253 gn_args += self.extra_gn_args_str 260 gn_args += self.extra_gn_args_str
254 return ['gn', 'gen', self.output_directory, '--args=%s' % gn_args] 261 return ['gn', 'gen', self.output_directory, '--args=%s' % gn_args]
255 262
256 def _GenNinjaCmd(self): 263 def _GenNinjaCmd(self):
257 cmd = ['ninja', '-C', self.output_directory] 264 cmd = ['ninja', '-C', self.output_directory]
258 cmd += ['-j', self.max_jobs] if self.max_jobs else [] 265 cmd += ['-j', self.max_jobs] if self.max_jobs else []
259 cmd += ['-l', self.max_load_average] if self.max_load_average else [] 266 cmd += ['-l', self.max_load_average] if self.max_load_average else []
260 cmd += [self.target] 267 cmd += [self.target]
261 return cmd 268 return cmd
262 269
263 def Run(self): 270 def Run(self):
264 """Run GN gen/ninja build and return the process returncode.""" 271 """Run GN gen/ninja build and return the process returncode."""
265 logging.info('Building: %s.', self.target) 272 logging.info('Building: %s (this might take a while).', self.target)
266 retcode = _RunCmd( 273 retcode = _RunCmd(
267 self._GenGnCmd(), verbose=True, exit_on_failure=False)[1] 274 self._GenGnCmd(), verbose=True, exit_on_failure=False)[1]
268 if retcode: 275 if retcode:
269 return retcode 276 return retcode
270 return _RunCmd( 277 return _RunCmd(
271 self._GenNinjaCmd(), verbose=True, exit_on_failure=False)[1] 278 self._GenNinjaCmd(), verbose=True, exit_on_failure=False)[1]
272 279
273 def DownloadUrl(self, rev): 280 def DownloadUrl(self, rev):
274 return self.download_bucket + 'full-build-linux_%s.zip' % rev 281 return self.download_bucket + 'full-build-linux_%s.zip' % rev
275 282
(...skipping 329 matching lines...) Expand 10 before | Expand all | Expand 10 after
605 logging.info('Downloading build artifacts for %s', archive.rev) 612 logging.info('Downloading build artifacts for %s', archive.rev)
606 # gsutil writes stdout and stderr to stderr, so pipe stdout and stderr to 613 # gsutil writes stdout and stderr to stderr, so pipe stdout and stderr to
607 # sys.stdout. 614 # sys.stdout.
608 retcode = subprocess.call( 615 retcode = subprocess.call(
609 [gsutil_path, 'cp', build.DownloadUrl(archive.rev), dl_dst], 616 [gsutil_path, 'cp', build.DownloadUrl(archive.rev), dl_dst],
610 stdout=sys.stdout, stderr=subprocess.STDOUT) 617 stdout=sys.stdout, stderr=subprocess.STDOUT)
611 if retcode: 618 if retcode:
612 _Die('unexpected error while downloading %s. It may no longer exist on ' 619 _Die('unexpected error while downloading %s. It may no longer exist on '
613 'the server or it may not have been uploaded yet (check %s). ' 620 'the server or it may not have been uploaded yet (check %s). '
614 'Otherwise, you may not have the correct access permissions.', 621 'Otherwise, you may not have the correct access permissions.',
615 build.DownloadUrl(archive.rev), _BUILDER_URL) 622 build.DownloadUrl(archive.rev), build.builder_url)
616 623
617 # Files needed for supersize and resource_sizes. Paths relative to out dir. 624 # Files needed for supersize and resource_sizes. Paths relative to out dir.
618 to_extract = [build.main_lib_path, build.map_file_path, 'args.gn'] 625 to_extract = [build.main_lib_path, build.map_file_path, 'args.gn']
619 if build.IsAndroid(): 626 if build.IsAndroid():
620 to_extract += ['build_vars.txt', build.apk_path, build.apk_path + '.size'] 627 to_extract += ['build_vars.txt', build.apk_path, build.apk_path + '.size']
621 extract_dir = dl_dst + '_' + 'unzipped' 628 extract_dir = dl_dst + '_' + 'unzipped'
622 # Storage bucket stores entire output directory including out/Release prefix. 629 # Storage bucket stores entire output directory including out/Release prefix.
623 logging.info('Extracting build artifacts') 630 logging.info('Extracting build artifacts')
624 with zipfile.ZipFile(dl_dst, 'r') as z: 631 with zipfile.ZipFile(dl_dst, 'r') as z:
625 _ExtractFiles(to_extract, build.download_output_dir, extract_dir, z) 632 _ExtractFiles(to_extract, build.download_output_dir, extract_dir, z)
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
668 shutil.rmtree(tmp_dir) 675 shutil.rmtree(tmp_dir)
669 676
670 677
671 def _SetRestoreFunc(subrepo): 678 def _SetRestoreFunc(subrepo):
672 branch = _GitCmd(['rev-parse', '--abbrev-ref', 'HEAD'], subrepo) 679 branch = _GitCmd(['rev-parse', '--abbrev-ref', 'HEAD'], subrepo)
673 atexit.register(lambda: _GitCmd(['checkout', branch], subrepo)) 680 atexit.register(lambda: _GitCmd(['checkout', branch], subrepo))
674 681
675 682
676 def main(): 683 def main():
677 parser = argparse.ArgumentParser( 684 parser = argparse.ArgumentParser(
678 description='Find the cause of APK size bloat.') 685 description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
679 parser.add_argument('--archive-directory', 686 parser.add_argument('--archive-directory',
680 default=_DEFAULT_ARCHIVE_DIR, 687 default=_DEFAULT_ARCHIVE_DIR,
681 help='Where results are stored.') 688 help='Where results are stored.')
682 parser.add_argument('rev', 689 parser.add_argument('rev',
683 help='Find binary size bloat for this commit.') 690 help='Find binary size bloat for this commit.')
684 parser.add_argument('--reference-rev', 691 parser.add_argument('--reference-rev',
685 help='Older rev to diff against. If not supplied, ' 692 help='Older rev to diff against. If not supplied, '
686 'the previous commit to rev will be used.') 693 'the previous commit to rev will be used.')
687 parser.add_argument('--all', 694 parser.add_argument('--all',
688 action='store_true', 695 action='store_true',
689 help='Build/download all revs from --reference-rev to ' 696 help='Build/download all revs from --reference-rev to '
690 'rev and diff the contiguous revisions.') 697 'rev and diff the contiguous revisions.')
691 parser.add_argument('--include-slow-options', 698 parser.add_argument('--include-slow-options',
692 action='store_true', 699 action='store_true',
693 help='Run some extra steps that take longer to complete. ' 700 help='Run some extra steps that take longer to complete. '
694 'This includes apk-patch-size estimation and ' 701 'This includes apk-patch-size estimation and '
695 'static-initializer counting.') 702 'static-initializer counting.')
696 parser.add_argument('--cloud', 703 parser.add_argument('--cloud',
697 action='store_true', 704 action='store_true',
698 help='Download build artifacts from perf builders ' 705 help='Download build artifacts from perf builders '
699 '(Android only, Googlers only).') 706 '(Googlers only).')
700 parser.add_argument('--depot-tools-path', 707 parser.add_argument('--depot-tools-path',
701 help='Custom path to depot tools. Needed for --cloud if ' 708 help='Custom path to depot tools. Needed for --cloud if '
702 'depot tools isn\'t in your PATH.') 709 'depot tools isn\'t in your PATH.')
703 parser.add_argument('--subrepo', 710 parser.add_argument('--subrepo',
704 help='Specify a subrepo directory to use. Gclient sync ' 711 help='Specify a subrepo directory to use. Gclient sync '
705 'will be skipped if this option is used and all git ' 712 'will be skipped if this option is used and all git '
706 'commands will be executed from the subrepo directory. ' 713 'commands will be executed from the subrepo '
707 'This option doesn\'t work with --cloud.') 714 'directory. This option doesn\'t work with --cloud.')
708 parser.add_argument('--silent', 715 parser.add_argument('-v',
716 '--verbose',
709 action='store_true', 717 action='store_true',
710 help='Less logging, no Ninja/GN output.') 718 help='Show commands executed, extra debugging output'
719 ', and Ninja/GN output')
711 720
712 build_group = parser.add_argument_group('ninja', 'Args to use with ninja/gn') 721 build_group = parser.add_argument_group('ninja arguments')
713 build_group.add_argument('-j', 722 build_group.add_argument('-j',
714 dest='max_jobs', 723 dest='max_jobs',
715 help='Run N jobs in parallel.') 724 help='Run N jobs in parallel.')
716 build_group.add_argument('-l', 725 build_group.add_argument('-l',
717 dest='max_load_average', 726 dest='max_load_average',
718 help='Do not start new jobs if the load average is ' 727 help='Do not start new jobs if the load average is '
719 'greater than N.') 728 'greater than N.')
720 build_group.add_argument('--no-goma', 729 build_group.add_argument('--no-goma',
721 action='store_false', 730 action='store_false',
722 dest='use_goma', 731 dest='use_goma',
723 default=True, 732 default=True,
724 help='Do not use goma when building with ninja.') 733 help='Do not use goma when building with ninja.')
725 build_group.add_argument('--target-os', 734 build_group.add_argument('--target-os',
726 default='android', 735 default='android',
727 choices=['android', 'linux'], 736 choices=['android', 'linux'],
728 help='target_os gn arg. Default: android.') 737 help='target_os gn arg. Default: android.')
729 build_group.add_argument('--output-directory', 738 build_group.add_argument('--output-directory',
730 default=_DEFAULT_OUT_DIR, 739 default=_DEFAULT_OUT_DIR,
731 help='ninja output directory. ' 740 help='ninja output directory. '
732 'Default: %s.' % _DEFAULT_OUT_DIR) 741 'Default: %s.' % _DEFAULT_OUT_DIR)
733 build_group.add_argument('--enable-chrome-android-internal', 742 build_group.add_argument('--enable-chrome-android-internal',
734 action='store_true', 743 action='store_true',
735 help='Allow downstream targets to be built.') 744 help='Allow downstream targets to be built.')
736 build_group.add_argument('--target', 745 build_group.add_argument('--target',
737 default=_DEFAULT_ANDROID_TARGET, 746 default=_DEFAULT_ANDROID_TARGET,
738 help='GN APK target to build. Ignored for Linux. ' 747 help='GN APK target to build. Ignored for Linux. '
739 'Default %s.' % _DEFAULT_ANDROID_TARGET) 748 'Default %s.' % _DEFAULT_ANDROID_TARGET)
740 if len(sys.argv) == 1: 749 if len(sys.argv) == 1:
741 parser.print_help() 750 parser.print_help()
742 sys.exit() 751 sys.exit()
743 args = parser.parse_args() 752 args = parser.parse_args()
744 log_level = logging.INFO if args.silent else logging.DEBUG 753 log_level = logging.DEBUG if args.verbose else logging.INFO
745 logging.basicConfig(level=log_level, 754 logging.basicConfig(level=log_level,
746 format='%(levelname).1s %(relativeCreated)6d %(message)s') 755 format='%(levelname).1s %(relativeCreated)6d %(message)s')
747 build = _BuildHelper(args) 756 build = _BuildHelper(args)
748 if build.IsCloud() and args.subrepo: 757 if build.IsCloud() and args.subrepo:
749 parser.error('--subrepo doesn\'t work with --cloud') 758 parser.error('--subrepo doesn\'t work with --cloud')
750 759
751 subrepo = args.subrepo or _SRC_ROOT 760 subrepo = args.subrepo or _SRC_ROOT
752 _EnsureDirectoryClean(subrepo) 761 _EnsureDirectoryClean(subrepo)
753 _SetRestoreFunc(subrepo) 762 _SetRestoreFunc(subrepo)
754 if build.IsLinux(): 763 if build.IsLinux():
755 _VerifyUserAccepts('Linux diffs have known deficiencies (crbug/717550).') 764 _VerifyUserAccepts('Linux diffs have known deficiencies (crbug/717550). ')
756 765
757 rev, reference_rev = _ValidateRevs( 766 rev, reference_rev = _ValidateRevs(
758 args.rev, args.reference_rev or args.rev + '^', subrepo) 767 args.rev, args.reference_rev or args.rev + '^', subrepo)
759 revs = _GenerateRevList(rev, reference_rev, args.all, subrepo) 768 revs = _GenerateRevList(rev, reference_rev, args.all, subrepo)
760 with _TmpCopyBinarySizeDir() as supersize_path: 769 with _TmpCopyBinarySizeDir() as supersize_path:
761 diffs = [NativeDiff(build.size_name, supersize_path)] 770 diffs = [NativeDiff(build.size_name, supersize_path)]
762 if build.IsAndroid(): 771 if build.IsAndroid():
763 diffs += [ 772 diffs += [
764 ResourceSizesDiff( 773 ResourceSizesDiff(
765 build.apk_name, slow_options=args.include_slow_options) 774 build.apk_name, slow_options=args.include_slow_options)
(...skipping 26 matching lines...) Expand all
792 801
793 if i != 0: 802 if i != 0:
794 diff_mngr.MaybeDiff(i - 1, i) 803 diff_mngr.MaybeDiff(i - 1, i)
795 804
796 diff_mngr.Summarize() 805 diff_mngr.Summarize()
797 806
798 807
799 if __name__ == '__main__': 808 if __name__ == '__main__':
800 sys.exit(main()) 809 sys.exit(main())
801 810
OLDNEW
« no previous file with comments | « tools/binary_size/README.md ('k') | tools/binary_size/libsupersize/describe.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698