312 lines
12 KiB
Python
312 lines
12 KiB
Python
# Copyright 2011 Google Inc. All Rights Reserved.
|
|
"""Script to build chrome with FDO and compare performance against no FDO."""
|
|
|
|
import getpass
|
|
import optparse
|
|
import os
|
|
import sys
|
|
|
|
import image_chromeos
|
|
import setup_chromeos
|
|
from cros_utils import command_executer
|
|
from cros_utils import misc
|
|
from cros_utils import logger
|
|
|
|
|
|
class Patcher(object):
|
|
|
|
def __init__(self, dir_to_patch, patch_file):
|
|
self._dir_to_patch = dir_to_patch
|
|
self._patch_file = patch_file
|
|
self._base_patch_command = 'patch -p0 %%s < %s' % patch_file
|
|
self._ce = command_executer.GetCommandExecuter()
|
|
|
|
def _RunPatchCommand(self, args):
|
|
patch_command = self._base_patch_command % args
|
|
command = ('cd %s && %s' % (self._dir_to_patch, patch_command))
|
|
return self._ce.RunCommand(command)
|
|
|
|
def _ApplyPatch(self, args):
|
|
full_args = '%s --dry-run' % args
|
|
ret = self._RunPatchCommand(full_args)
|
|
if ret:
|
|
raise RuntimeError('Patch dry run failed!')
|
|
ret = self._RunPatchCommand(args)
|
|
if ret:
|
|
raise RuntimeError('Patch application failed!')
|
|
|
|
def __enter__(self):
|
|
self._ApplyPatch('')
|
|
|
|
def __exit__(self, type, value, traceback):
|
|
self._ApplyPatch('-R')
|
|
|
|
|
|
class FDOComparator(object):
|
|
|
|
def __init__(self, board, remotes, ebuild_version, plus_pgo, minus_pgo,
|
|
update_pgo, chromeos_root):
|
|
self._board = board
|
|
self._remotes = remotes
|
|
self._ebuild_version = ebuild_version
|
|
self._remote = remotes.split(',')[0]
|
|
self._chromeos_root = chromeos_root
|
|
self._profile_dir = 'profile_dir'
|
|
self._profile_path = os.path.join(self._chromeos_root, 'src', 'scripts',
|
|
os.path.basename(self._profile_dir))
|
|
self._plus_pgo = plus_pgo
|
|
self._minus_pgo = minus_pgo
|
|
self._update_pgo = update_pgo
|
|
|
|
self._ce = command_executer.GetCommandExecuter()
|
|
self._l = logger.GetLogger()
|
|
|
|
def _CheckoutChromeOS(self):
|
|
if not os.path.exists(self._chromeos_root):
|
|
setup_chromeos_args = [setup_chromeos.__file__,
|
|
'--dir=%s' % self._chromeos_root, '--minilayout']
|
|
setup_chromeos.Main(setup_chromeos_args)
|
|
|
|
def _BuildChromeOSUsingBinaries(self):
|
|
image_dir = misc.GetImageDir(self._chromeos_root, self._board)
|
|
command = 'equery-%s l chromeos' % self._board
|
|
ret = self._ce.ChrootRunCommand(self._chromeos_root, command)
|
|
if ret:
|
|
command = misc.GetSetupBoardCommand(self._board, usepkg=True)
|
|
ret = self._ce.ChrootRunCommand(self._chromeos_root, command)
|
|
if ret:
|
|
raise RuntimeError("Couldn't run setup_board!")
|
|
command = misc.GetBuildPackagesCommand(self._board, True)
|
|
ret = self._ce.ChrootRunCommand(self._chromeos_root, command)
|
|
if ret:
|
|
raise RuntimeError("Couldn't run build_packages!")
|
|
|
|
def _ReportMismatches(self, build_log):
|
|
mismatch_signature = '-Wcoverage-mismatch'
|
|
mismatches = build_log.count(mismatch_signature)
|
|
self._l.LogOutput('Total mismatches: %s' % mismatches)
|
|
stale_files = set([])
|
|
for line in build_log.splitlines():
|
|
if mismatch_signature in line:
|
|
filename = line.split(':')[0]
|
|
stale_files.add(filename)
|
|
self._l.LogOutput('Total stale files: %s' % len(stale_files))
|
|
|
|
def _BuildChromeAndImage(self,
|
|
ebuild_version='',
|
|
env_dict={},
|
|
cflags='',
|
|
cxxflags='',
|
|
ldflags='',
|
|
label='',
|
|
build_image_args=''):
|
|
env_string = misc.GetEnvStringFromDict(env_dict)
|
|
if not label:
|
|
label = ' '.join([env_string, cflags, cxxflags, ldflags, ebuild_version])
|
|
label = label.strip()
|
|
label = misc.GetFilenameFromString(label)
|
|
if not misc.DoesLabelExist(self._chromeos_root, self._board, label):
|
|
build_chrome_browser_args = ['--clean', '--chromeos_root=%s' %
|
|
self._chromeos_root, '--board=%s' %
|
|
self._board, '--env=%r' % env_string,
|
|
'--cflags=%r' % cflags, '--cxxflags=%r' %
|
|
cxxflags, '--ldflags=%r' % ldflags,
|
|
'--ebuild_version=%s' % ebuild_version,
|
|
'--build_image_args=%s' % build_image_args]
|
|
|
|
build_chrome_browser = os.path.join(
|
|
os.path.dirname(__file__), '..', 'build_chrome_browser.py')
|
|
command = 'python %s %s' % (build_chrome_browser,
|
|
' '.join(build_chrome_browser_args))
|
|
ret, out, err = self._ce.RunCommandWOutput(command)
|
|
if '-fprofile-use' in cxxflags:
|
|
self._ReportMismatches(out)
|
|
|
|
if ret:
|
|
raise RuntimeError("Couldn't build chrome browser!")
|
|
misc.LabelLatestImage(self._chromeos_root, self._board, label)
|
|
return label
|
|
|
|
def _TestLabels(self, labels):
|
|
experiment_file = 'pgo_experiment.txt'
|
|
experiment_header = """
|
|
board: %s
|
|
remote: %s
|
|
""" % (self._board, self._remotes)
|
|
experiment_tests = """
|
|
benchmark: desktopui_PyAutoPerfTests {
|
|
iterations: 1
|
|
}
|
|
"""
|
|
|
|
with open(experiment_file, 'w') as f:
|
|
print >> f, experiment_header
|
|
print >> f, experiment_tests
|
|
for label in labels:
|
|
# TODO(asharif): Fix crosperf so it accepts labels with symbols
|
|
crosperf_label = label
|
|
crosperf_label = crosperf_label.replace('-', 'minus')
|
|
crosperf_label = crosperf_label.replace('+', 'plus')
|
|
experiment_image = """
|
|
%s {
|
|
chromeos_image: %s
|
|
}
|
|
""" % (crosperf_label, os.path.join(
|
|
misc.GetImageDir(self._chromeos_root, self._board), label,
|
|
'chromiumos_test_image.bin'))
|
|
print >> f, experiment_image
|
|
crosperf = os.path.join(
|
|
os.path.dirname(__file__), '..', 'crosperf', 'crosperf')
|
|
command = '%s %s' % (crosperf, experiment_file)
|
|
ret = self._ce.RunCommand(command)
|
|
if ret:
|
|
raise RuntimeError("Couldn't run crosperf!")
|
|
|
|
def _ImageRemote(self, label):
|
|
image_path = os.path.join(
|
|
misc.GetImageDir(self._chromeos_root,
|
|
self._board), label, 'chromiumos_test_image.bin')
|
|
image_chromeos_args = [image_chromeos.__file__, '--chromeos_root=%s' %
|
|
self._chromeos_root, '--image=%s' % image_path,
|
|
'--remote=%s' % self._remote,
|
|
'--board=%s' % self._board]
|
|
image_chromeos.Main(image_chromeos_args)
|
|
|
|
def _ProfileRemote(self):
|
|
profile_cycler = os.path.join(
|
|
os.path.dirname(__file__), 'profile_cycler.py')
|
|
profile_cycler_args = ['--chromeos_root=%s' % self._chromeos_root,
|
|
'--cycler=all', '--board=%s' % self._board,
|
|
'--profile_dir=%s' % self._profile_path,
|
|
'--remote=%s' % self._remote]
|
|
command = 'python %s %s' % (profile_cycler, ' '.join(profile_cycler_args))
|
|
ret = self._ce.RunCommand(command)
|
|
if ret:
|
|
raise RuntimeError("Couldn't profile cycler!")
|
|
|
|
def _BuildGenerateImage(self):
|
|
# TODO(asharif): add cflags as well.
|
|
labels_list = ['fprofile-generate', self._ebuild_version]
|
|
label = '_'.join(labels_list)
|
|
generate_label = self._BuildChromeAndImage(
|
|
env_dict={'USE': 'chrome_internal -pgo pgo_generate'},
|
|
label=label,
|
|
ebuild_version=self._ebuild_version,
|
|
build_image_args='--rootfs_boost_size=400')
|
|
return generate_label
|
|
|
|
def _BuildUseImage(self):
|
|
ctarget = misc.GetCtargetFromBoard(self._board, self._chromeos_root)
|
|
chroot_profile_dir = os.path.join('/home/%s/trunk' % getpass.getuser(),
|
|
'src', 'scripts', self._profile_dir,
|
|
ctarget)
|
|
cflags = ('-fprofile-use '
|
|
'-fprofile-correction '
|
|
'-Wno-error '
|
|
'-fdump-tree-optimized-blocks-lineno '
|
|
'-fdump-ipa-profile-blocks-lineno '
|
|
'-fno-vpt '
|
|
'-fprofile-dir=%s' % chroot_profile_dir)
|
|
labels_list = ['updated_pgo', self._ebuild_version]
|
|
label = '_'.join(labels_list)
|
|
pgo_use_label = self._BuildChromeAndImage(
|
|
env_dict={'USE': 'chrome_internal -pgo'},
|
|
cflags=cflags,
|
|
cxxflags=cflags,
|
|
ldflags=cflags,
|
|
label=label,
|
|
ebuild_version=self._ebuild_version)
|
|
return pgo_use_label
|
|
|
|
def DoAll(self):
|
|
self._CheckoutChromeOS()
|
|
self._BuildChromeOSUsingBinaries()
|
|
labels = []
|
|
|
|
if self._minus_pgo:
|
|
minus_pgo = self._BuildChromeAndImage(
|
|
env_dict={'USE': 'chrome_internal -pgo'},
|
|
ebuild_version=self._ebuild_version)
|
|
labels.append(minus_pgo)
|
|
if self._plus_pgo:
|
|
plus_pgo = self._BuildChromeAndImage(
|
|
env_dict={'USE': 'chrome_internal pgo'},
|
|
ebuild_version=self._ebuild_version)
|
|
labels.append(plus_pgo)
|
|
|
|
if self._update_pgo:
|
|
if not os.path.exists(self._profile_path):
|
|
# Build Chrome with -fprofile-generate
|
|
generate_label = self._BuildGenerateImage()
|
|
# Image to the remote box.
|
|
self._ImageRemote(generate_label)
|
|
# Profile it using all page cyclers.
|
|
self._ProfileRemote()
|
|
|
|
# Use the profile directory to rebuild it.
|
|
updated_pgo_label = self._BuildUseImage()
|
|
labels.append(updated_pgo_label)
|
|
|
|
# Run crosperf on all images now.
|
|
self._TestLabels(labels)
|
|
return 0
|
|
|
|
|
|
def Main(argv):
|
|
"""The main function."""
|
|
# Common initializations
|
|
### command_executer.InitCommandExecuter(True)
|
|
command_executer.InitCommandExecuter()
|
|
parser = optparse.OptionParser()
|
|
parser.add_option('--remote',
|
|
dest='remote',
|
|
help='Remote machines to run tests on.')
|
|
parser.add_option('--board',
|
|
dest='board',
|
|
default='x86-zgb',
|
|
help='The target board.')
|
|
parser.add_option('--ebuild_version',
|
|
dest='ebuild_version',
|
|
default='',
|
|
help='The Chrome ebuild version to use.')
|
|
parser.add_option('--plus_pgo',
|
|
dest='plus_pgo',
|
|
action='store_true',
|
|
default=False,
|
|
help='Build USE=+pgo.')
|
|
parser.add_option('--minus_pgo',
|
|
dest='minus_pgo',
|
|
action='store_true',
|
|
default=False,
|
|
help='Build USE=-pgo.')
|
|
parser.add_option('--update_pgo',
|
|
dest='update_pgo',
|
|
action='store_true',
|
|
default=False,
|
|
help='Update pgo and build Chrome with the update.')
|
|
parser.add_option('--chromeos_root',
|
|
dest='chromeos_root',
|
|
default=False,
|
|
help='The chromeos root directory')
|
|
options, _ = parser.parse_args(argv)
|
|
if not options.board:
|
|
print 'Please give a board.'
|
|
return 1
|
|
if not options.remote:
|
|
print 'Please give at least one remote machine.'
|
|
return 1
|
|
if not options.chromeos_root:
|
|
print 'Please provide the chromeos root directory.'
|
|
return 1
|
|
if not any((options.minus_pgo, options.plus_pgo, options.update_pgo)):
|
|
print 'Please provide at least one build option.'
|
|
return 1
|
|
fc = FDOComparator(options.board, options.remote, options.ebuild_version,
|
|
options.plus_pgo, options.minus_pgo, options.update_pgo,
|
|
os.path.expanduser(options.chromeos_root))
|
|
return fc.DoAll()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
retval = Main(sys.argv)
|
|
sys.exit(retval)
|