blob: 8684653f6bd5e8c263325301f1c03e369c9622d9 [file] [log] [blame]
Caroline Ticef6ef4392017-04-06 17:16:05 -07001#!/usr/bin/env python2
asharif96f59692013-02-16 03:13:36 +00002
3# Script to test different toolchains against ChromeOS benchmarks.
Caroline Tice88272d42016-01-13 09:48:29 -08004"""Toolchain team nightly performance test script (local builds)."""
5
6from __future__ import print_function
7
8import argparse
cmtice7cdb11a2015-05-28 10:24:41 -07009import datetime
asharif96f59692013-02-16 03:13:36 +000010import os
11import sys
12import build_chromeos
13import setup_chromeos
Caroline Tice88272d42016-01-13 09:48:29 -080014from cros_utils import command_executer
15from cros_utils import misc
16from cros_utils import logger
asharif96f59692013-02-16 03:13:36 +000017
Luis Lozanof2a3ef42015-12-15 13:49:30 -080018CROSTC_ROOT = '/usr/local/google/crostc'
19MAIL_PROGRAM = '~/var/bin/mail-sheriff'
Luis Lozanof2a3ef42015-12-15 13:49:30 -080020PENDING_ARCHIVES_DIR = os.path.join(CROSTC_ROOT, 'pending_archives')
21NIGHTLY_TESTS_DIR = os.path.join(CROSTC_ROOT, 'nightly_test_reports')
asharif96f59692013-02-16 03:13:36 +000022
cmtice94bc4702014-05-29 16:29:04 -070023
asharif96f59692013-02-16 03:13:36 +000024class GCCConfig(object):
Caroline Tice88272d42016-01-13 09:48:29 -080025 """GCC configuration class."""
Luis Lozanof2a3ef42015-12-15 13:49:30 -080026
asharif96f59692013-02-16 03:13:36 +000027 def __init__(self, githash):
28 self.githash = githash
29
30
Caroline Tice88272d42016-01-13 09:48:29 -080031class ToolchainConfig(object):
32 """Toolchain configuration class."""
Luis Lozanof2a3ef42015-12-15 13:49:30 -080033
Caroline Tice88272d42016-01-13 09:48:29 -080034 def __init__(self, gcc_config=None):
asharif96f59692013-02-16 03:13:36 +000035 self.gcc_config = gcc_config
36
37
38class ChromeOSCheckout(object):
Caroline Tice88272d42016-01-13 09:48:29 -080039 """Main class for checking out, building and testing ChromeOS."""
Luis Lozanof2a3ef42015-12-15 13:49:30 -080040
asharif96f59692013-02-16 03:13:36 +000041 def __init__(self, board, chromeos_root):
42 self._board = board
43 self._chromeos_root = chromeos_root
44 self._ce = command_executer.GetCommandExecuter()
45 self._l = logger.GetLogger()
cmtice56fb7162014-06-18 11:32:15 -070046 self._build_num = None
asharif96f59692013-02-16 03:13:36 +000047
asharif3e38de02013-02-19 19:34:59 +000048 def _DeleteChroot(self):
Luis Lozanof2a3ef42015-12-15 13:49:30 -080049 command = 'cd %s; cros_sdk --delete' % self._chromeos_root
asharif3e38de02013-02-19 19:34:59 +000050 return self._ce.RunCommand(command)
51
asharif67973582013-02-19 20:19:40 +000052 def _DeleteCcahe(self):
53 # crosbug.com/34956
Luis Lozanof2a3ef42015-12-15 13:49:30 -080054 command = 'sudo rm -rf %s' % os.path.join(self._chromeos_root, '.cache')
asharif67973582013-02-19 20:19:40 +000055 return self._ce.RunCommand(command)
56
cmtice56fb7162014-06-18 11:32:15 -070057 def _GetBuildNumber(self):
Caroline Tice88272d42016-01-13 09:48:29 -080058 """Get the build number of the ChromeOS image from the chroot.
59
60 This function assumes a ChromeOS image has been built in the chroot.
cmtice56fb7162014-06-18 11:32:15 -070061 It translates the 'latest' symlink in the
62 <chroot>/src/build/images/<board> directory, to find the actual
63 ChromeOS build number for the image that was built. For example, if
64 src/build/image/lumpy/latest -> R37-5982.0.2014_06_23_0454-a1, then
65 This function would parse it out and assign 'R37-5982' to self._build_num.
66 This is used to determine the official, vanilla build to use for
67 comparison tests.
68 """
69 # Get the path to 'latest'
Luis Lozanof2a3ef42015-12-15 13:49:30 -080070 sym_path = os.path.join(
71 misc.GetImageDir(self._chromeos_root, self._board), 'latest')
cmtice56fb7162014-06-18 11:32:15 -070072 # Translate the symlink to its 'real' path.
73 real_path = os.path.realpath(sym_path)
74 # Break up the path and get the last piece
75 # (e.g. 'R37-5982.0.2014_06_23_0454-a1"
Luis Lozanof2a3ef42015-12-15 13:49:30 -080076 path_pieces = real_path.split('/')
cmtice56fb7162014-06-18 11:32:15 -070077 last_piece = path_pieces[-1]
78 # Break this piece into the image number + other pieces, and get the
79 # image number [ 'R37-5982', '0', '2014_06_23_0454-a1']
Luis Lozanof2a3ef42015-12-15 13:49:30 -080080 image_parts = last_piece.split('.')
cmtice56fb7162014-06-18 11:32:15 -070081 self._build_num = image_parts[0]
82
Caroline Tice88272d42016-01-13 09:48:29 -080083 def _BuildLabelName(self, config):
Luis Lozanof2a3ef42015-12-15 13:49:30 -080084 pieces = config.split('/')
Caroline Tice80eab982015-11-04 14:03:14 -080085 compiler_version = pieces[-1]
Luis Lozanof2a3ef42015-12-15 13:49:30 -080086 label = compiler_version + '_tot_afdo'
Caroline Tice80eab982015-11-04 14:03:14 -080087 return label
88
Luis Lozanof2a3ef42015-12-15 13:49:30 -080089 def _BuildAndImage(self, label=''):
asharif96f59692013-02-16 03:13:36 +000090 if (not label or
91 not misc.DoesLabelExist(self._chromeos_root, self._board, label)):
Manoj Guptaaee96b72016-10-24 13:43:28 -070092 build_chromeos_args = [
93 build_chromeos.__file__, '--chromeos_root=%s' % self._chromeos_root,
94 '--board=%s' % self._board, '--rebuild'
95 ]
asharife6b72fe2013-02-19 19:58:18 +000096 if self._public:
Luis Lozanof2a3ef42015-12-15 13:49:30 -080097 build_chromeos_args.append('--env=USE=-chrome_internal')
cmtice56fb7162014-06-18 11:32:15 -070098
asharif96f59692013-02-16 03:13:36 +000099 ret = build_chromeos.Main(build_chromeos_args)
cmtice7f3190b2015-05-22 14:14:51 -0700100 if ret != 0:
101 raise RuntimeError("Couldn't build ChromeOS!")
cmtice56fb7162014-06-18 11:32:15 -0700102
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800103 if not self._build_num:
cmtice56fb7162014-06-18 11:32:15 -0700104 self._GetBuildNumber()
105 # Check to see if we need to create the symbolic link for the vanilla
106 # image, and do so if appropriate.
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800107 if not misc.DoesLabelExist(self._chromeos_root, self._board, 'vanilla'):
108 build_name = '%s-release/%s.0.0' % (self._board, self._build_num)
109 full_vanilla_path = os.path.join(os.getcwd(), self._chromeos_root,
110 'chroot/tmp', build_name)
cmtice56fb7162014-06-18 11:32:15 -0700111 misc.LabelLatestImage(self._chromeos_root, self._board, label,
112 full_vanilla_path)
113 else:
asharif96f59692013-02-16 03:13:36 +0000114 misc.LabelLatestImage(self._chromeos_root, self._board, label)
115 return label
116
cmtice56fb7162014-06-18 11:32:15 -0700117 def _SetupBoard(self, env_dict, usepkg_flag, clobber_flag):
asharif96f59692013-02-16 03:13:36 +0000118 env_string = misc.GetEnvStringFromDict(env_dict)
Manoj Guptaaee96b72016-10-24 13:43:28 -0700119 command = ('%s %s' % (env_string, misc.GetSetupBoardCommand(
120 self._board, usepkg=usepkg_flag, force=clobber_flag)))
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800121 ret = self._ce.ChrootRunCommand(self._chromeos_root, command)
cmtice56fb7162014-06-18 11:32:15 -0700122 error_str = "Could not setup board: '%s'" % command
123 assert ret == 0, error_str
asharif96f59692013-02-16 03:13:36 +0000124
125 def _UnInstallToolchain(self):
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800126 command = ('sudo CLEAN_DELAY=0 emerge -C cross-%s/gcc' %
127 misc.GetCtargetFromBoard(self._board, self._chromeos_root))
128 ret = self._ce.ChrootRunCommand(self._chromeos_root, command)
cmtice7f3190b2015-05-22 14:14:51 -0700129 if ret != 0:
130 raise RuntimeError("Couldn't uninstall the toolchain!")
asharif96f59692013-02-16 03:13:36 +0000131
132 def _CheckoutChromeOS(self):
133 # TODO(asharif): Setup a fixed ChromeOS version (quarterly snapshot).
134 if not os.path.exists(self._chromeos_root):
Rahul Chaudhry4d4565e2016-01-27 10:46:09 -0800135 setup_chromeos_args = ['--dir=%s' % self._chromeos_root]
asharife6b72fe2013-02-19 19:58:18 +0000136 if self._public:
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800137 setup_chromeos_args.append('--public')
asharif5fe40e22013-02-19 19:58:50 +0000138 ret = setup_chromeos.Main(setup_chromeos_args)
cmtice7f3190b2015-05-22 14:14:51 -0700139 if ret != 0:
140 raise RuntimeError("Couldn't run setup_chromeos!")
asharif96f59692013-02-16 03:13:36 +0000141
142 def _BuildToolchain(self, config):
cmtice56fb7162014-06-18 11:32:15 -0700143 # Call setup_board for basic, vanilla setup.
144 self._SetupBoard({}, usepkg_flag=True, clobber_flag=False)
145 # Now uninstall the vanilla compiler and setup/build our custom
146 # compiler.
asharif96f59692013-02-16 03:13:36 +0000147 self._UnInstallToolchain()
Manoj Guptaaee96b72016-10-24 13:43:28 -0700148 envdict = {
149 'USE': 'git_gcc',
150 'GCC_GITHASH': config.gcc_config.githash,
151 'EMERGE_DEFAULT_OPTS': '--exclude=gcc'
152 }
cmtice56fb7162014-06-18 11:32:15 -0700153 self._SetupBoard(envdict, usepkg_flag=False, clobber_flag=False)
asharif96f59692013-02-16 03:13:36 +0000154
155
156class ToolchainComparator(ChromeOSCheckout):
Caroline Tice88272d42016-01-13 09:48:29 -0800157 """Main class for running tests and generating reports."""
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800158
159 def __init__(self,
160 board,
161 remotes,
162 configs,
163 clean,
164 public,
165 force_mismatch,
166 noschedv2=False):
asharif96f59692013-02-16 03:13:36 +0000167 self._board = board
168 self._remotes = remotes
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800169 self._chromeos_root = 'chromeos'
asharif96f59692013-02-16 03:13:36 +0000170 self._configs = configs
asharif3e38de02013-02-19 19:34:59 +0000171 self._clean = clean
asharife6b72fe2013-02-19 19:58:18 +0000172 self._public = public
asharif58a8c9f2013-02-19 20:42:43 +0000173 self._force_mismatch = force_mismatch
asharif96f59692013-02-16 03:13:36 +0000174 self._ce = command_executer.GetCommandExecuter()
175 self._l = logger.GetLogger()
cmtice7f3190b2015-05-22 14:14:51 -0700176 timestamp = datetime.datetime.strftime(datetime.datetime.now(),
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800177 '%Y-%m-%d_%H:%M:%S')
Manoj Guptaaee96b72016-10-24 13:43:28 -0700178 self._reports_dir = os.path.join(
179 NIGHTLY_TESTS_DIR,
180 '%s.%s' % (timestamp, board),)
Han Shen43494292015-09-14 10:26:40 -0700181 self._noschedv2 = noschedv2
asharif96f59692013-02-16 03:13:36 +0000182 ChromeOSCheckout.__init__(self, board, self._chromeos_root)
183
cmticea6255d02014-01-10 10:27:22 -0800184 def _FinishSetup(self):
185 # Get correct .boto file
186 current_dir = os.getcwd()
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800187 src = '/usr/local/google/home/mobiletc-prebuild/.boto'
cmticea6255d02014-01-10 10:27:22 -0800188 dest = os.path.join(current_dir, self._chromeos_root,
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800189 'src/private-overlays/chromeos-overlay/'
190 'googlestorage_account.boto')
cmticea6255d02014-01-10 10:27:22 -0800191 # Copy the file to the correct place
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800192 copy_cmd = 'cp %s %s' % (src, dest)
Caroline Tice88272d42016-01-13 09:48:29 -0800193 retv = self._ce.RunCommand(copy_cmd)
194 if retv != 0:
cmtice7f3190b2015-05-22 14:14:51 -0700195 raise RuntimeError("Couldn't copy .boto file for google storage.")
cmticea6255d02014-01-10 10:27:22 -0800196
197 # Fix protections on ssh key
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800198 command = ('chmod 600 /var/cache/chromeos-cache/distfiles/target'
199 '/chrome-src-internal/src/third_party/chromite/ssh_keys'
200 '/testing_rsa')
Caroline Tice88272d42016-01-13 09:48:29 -0800201 retv = self._ce.ChrootRunCommand(self._chromeos_root, command)
202 if retv != 0:
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800203 raise RuntimeError('chmod for testing_rsa failed')
cmticea6255d02014-01-10 10:27:22 -0800204
asharif96f59692013-02-16 03:13:36 +0000205 def _TestLabels(self, labels):
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800206 experiment_file = 'toolchain_experiment.txt'
207 image_args = ''
asharif58a8c9f2013-02-19 20:42:43 +0000208 if self._force_mismatch:
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800209 image_args = '--force-mismatch'
asharif96f59692013-02-16 03:13:36 +0000210 experiment_header = """
211 board: %s
212 remote: %s
cmticed1f03b82015-06-30 15:19:23 -0700213 retries: 1
asharif96f59692013-02-16 03:13:36 +0000214 """ % (self._board, self._remotes)
215 experiment_tests = """
cmtice0c84ea72015-06-25 14:22:36 -0700216 benchmark: all_toolchain_perf {
cmtice04403882013-11-04 16:38:37 -0500217 suite: telemetry_Crosperf
cmtice6de7f8f2014-03-14 14:08:21 -0700218 iterations: 3
asharif96f59692013-02-16 03:13:36 +0000219 }
220 """
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800221
222 with open(experiment_file, 'w') as f:
Caroline Tice88272d42016-01-13 09:48:29 -0800223 f.write(experiment_header)
224 f.write(experiment_tests)
asharif96f59692013-02-16 03:13:36 +0000225 for label in labels:
226 # TODO(asharif): Fix crosperf so it accepts labels with symbols
227 crosperf_label = label
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800228 crosperf_label = crosperf_label.replace('-', '_')
229 crosperf_label = crosperf_label.replace('+', '_')
230 crosperf_label = crosperf_label.replace('.', '')
cmtice56fb7162014-06-18 11:32:15 -0700231
232 # Use the official build instead of building vanilla ourselves.
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800233 if label == 'vanilla':
cmtice56fb7162014-06-18 11:32:15 -0700234 build_name = '%s-release/%s.0.0' % (self._board, self._build_num)
235
236 # Now add 'official build' to test file.
237 official_image = """
238 official_image {
239 chromeos_root: %s
240 build: %s
241 }
242 """ % (self._chromeos_root, build_name)
Caroline Tice88272d42016-01-13 09:48:29 -0800243 f.write(official_image)
cmtice56fb7162014-06-18 11:32:15 -0700244
cmtice94bc4702014-05-29 16:29:04 -0700245 else:
cmtice56fb7162014-06-18 11:32:15 -0700246 experiment_image = """
247 %s {
248 chromeos_image: %s
249 image_args: %s
250 }
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800251 """ % (crosperf_label, os.path.join(
252 misc.GetImageDir(self._chromeos_root, self._board), label,
253 'chromiumos_test_image.bin'), image_args)
Caroline Tice88272d42016-01-13 09:48:29 -0800254 f.write(experiment_image)
cmtice56fb7162014-06-18 11:32:15 -0700255
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800256 crosperf = os.path.join(os.path.dirname(__file__), 'crosperf', 'crosperf')
Han Shen43494292015-09-14 10:26:40 -0700257 noschedv2_opts = '--noschedv2' if self._noschedv2 else ''
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800258 command = ('{crosperf} --no_email=True --results_dir={r_dir} '
259 '--json_report=True {noschedv2_opts} {exp_file}').format(
260 crosperf=crosperf,
261 r_dir=self._reports_dir,
262 noschedv2_opts=noschedv2_opts,
263 exp_file=experiment_file)
cmticeaa700b02015-06-12 13:26:47 -0700264
asharif96f59692013-02-16 03:13:36 +0000265 ret = self._ce.RunCommand(command)
cmtice7f3190b2015-05-22 14:14:51 -0700266 if ret != 0:
Manoj Guptaaee96b72016-10-24 13:43:28 -0700267 raise RuntimeError('Crosperf execution error!')
Caroline Ticeebbc3da2015-09-03 10:27:20 -0700268 else:
269 # Copy json report to pending archives directory.
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800270 command = 'cp %s/*.json %s/.' % (self._reports_dir, PENDING_ARCHIVES_DIR)
Caroline Ticeebbc3da2015-09-03 10:27:20 -0700271 ret = self._ce.RunCommand(command)
cmtice7f3190b2015-05-22 14:14:51 -0700272 return
cmtice56fb7162014-06-18 11:32:15 -0700273
cmtice7f3190b2015-05-22 14:14:51 -0700274 def _SendEmail(self):
275 """Find email msesage generated by crosperf and send it."""
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800276 filename = os.path.join(self._reports_dir, 'msg_body.html')
cmtice7f3190b2015-05-22 14:14:51 -0700277 if (os.path.exists(filename) and
278 os.path.exists(os.path.expanduser(MAIL_PROGRAM))):
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800279 command = ('cat %s | %s -s "Nightly test results, %s" -team -html' %
280 (filename, MAIL_PROGRAM, self._board))
cmtice7f3190b2015-05-22 14:14:51 -0700281 self._ce.RunCommand(command)
asharif96f59692013-02-16 03:13:36 +0000282
283 def DoAll(self):
284 self._CheckoutChromeOS()
asharif96f59692013-02-16 03:13:36 +0000285 labels = []
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800286 labels.append('vanilla')
asharif96f59692013-02-16 03:13:36 +0000287 for config in self._configs:
Caroline Tice88272d42016-01-13 09:48:29 -0800288 label = self._BuildLabelName(config.gcc_config.githash)
289 if not misc.DoesLabelExist(self._chromeos_root, self._board, label):
asharif96f59692013-02-16 03:13:36 +0000290 self._BuildToolchain(config)
291 label = self._BuildAndImage(label)
292 labels.append(label)
cmticea6255d02014-01-10 10:27:22 -0800293 self._FinishSetup()
cmticeb4588092015-05-27 08:07:50 -0700294 self._TestLabels(labels)
cmtice7f3190b2015-05-22 14:14:51 -0700295 self._SendEmail()
asharif3e38de02013-02-19 19:34:59 +0000296 if self._clean:
297 ret = self._DeleteChroot()
cmtice7f3190b2015-05-22 14:14:51 -0700298 if ret != 0:
299 return ret
asharif67973582013-02-19 20:19:40 +0000300 ret = self._DeleteCcahe()
cmtice7f3190b2015-05-22 14:14:51 -0700301 if ret != 0:
302 return ret
asharif96f59692013-02-16 03:13:36 +0000303 return 0
304
305
306def Main(argv):
307 """The main function."""
308 # Common initializations
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800309 ### command_executer.InitCommandExecuter(True)
asharif96f59692013-02-16 03:13:36 +0000310 command_executer.InitCommandExecuter()
Caroline Tice88272d42016-01-13 09:48:29 -0800311 parser = argparse.ArgumentParser()
Manoj Guptaaee96b72016-10-24 13:43:28 -0700312 parser.add_argument(
313 '--remote', dest='remote', help='Remote machines to run tests on.')
314 parser.add_argument(
315 '--board', dest='board', default='x86-alex', help='The target board.')
316 parser.add_argument(
317 '--githashes',
318 dest='githashes',
319 default='master',
320 help='The gcc githashes to test.')
321 parser.add_argument(
322 '--clean',
323 dest='clean',
324 default=False,
325 action='store_true',
326 help='Clean the chroot after testing.')
327 parser.add_argument(
328 '--public',
329 dest='public',
330 default=False,
331 action='store_true',
332 help='Use the public checkout/build.')
333 parser.add_argument(
334 '--force-mismatch',
335 dest='force_mismatch',
336 default='',
337 help='Force the image regardless of board mismatch')
338 parser.add_argument(
339 '--noschedv2',
340 dest='noschedv2',
341 action='store_true',
342 default=False,
343 help='Pass --noschedv2 to crosperf.')
Caroline Tice88272d42016-01-13 09:48:29 -0800344 options = parser.parse_args(argv)
asharif96f59692013-02-16 03:13:36 +0000345 if not options.board:
Caroline Tice88272d42016-01-13 09:48:29 -0800346 print('Please give a board.')
asharif96f59692013-02-16 03:13:36 +0000347 return 1
348 if not options.remote:
Caroline Tice88272d42016-01-13 09:48:29 -0800349 print('Please give at least one remote machine.')
asharif96f59692013-02-16 03:13:36 +0000350 return 1
351 toolchain_configs = []
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800352 for githash in options.githashes.split(','):
asharif96f59692013-02-16 03:13:36 +0000353 gcc_config = GCCConfig(githash=githash)
354 toolchain_config = ToolchainConfig(gcc_config=gcc_config)
355 toolchain_configs.append(toolchain_config)
asharif3e38de02013-02-19 19:34:59 +0000356 fc = ToolchainComparator(options.board, options.remote, toolchain_configs,
asharif58a8c9f2013-02-19 20:42:43 +0000357 options.clean, options.public,
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800358 options.force_mismatch, options.noschedv2)
asharif96f59692013-02-16 03:13:36 +0000359 return fc.DoAll()
360
361
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800362if __name__ == '__main__':
Rahul Chaudhry748254e2016-01-25 16:49:21 -0800363 retval = Main(sys.argv[1:])
asharif96f59692013-02-16 03:13:36 +0000364 sys.exit(retval)