blob: 033f3ec7cffdc9be108c9b913af66b796b5983f5 [file] [log] [blame]
asharif96f59692013-02-16 03:13:36 +00001#!/usr/bin/python
2
3# Script to test different toolchains against ChromeOS benchmarks.
cmtice7cdb11a2015-05-28 10:24:41 -07004import datetime
asharif96f59692013-02-16 03:13:36 +00005import optparse
6import os
7import sys
8import build_chromeos
9import setup_chromeos
cmtice94bc4702014-05-29 16:29:04 -070010import time
asharif96f59692013-02-16 03:13:36 +000011from utils import command_executer
12from utils import misc
13from utils import logger
14
15
cmtice94bc4702014-05-29 16:29:04 -070016WEEKLY_REPORTS_ROOT="/usr/local/google/crostc/weekly_test_data"
cmtice23130bd2014-07-15 11:19:29 -070017AFDO_BOARDS = ["butterfly", "lumpy", "stumpy", "stout", "parrot", "parrot_ivb"]
cmtice7f3190b2015-05-22 14:14:51 -070018MAIL_PROGRAM = "~/var/bin/mail-sheriff"
cmtice94bc4702014-05-29 16:29:04 -070019
asharif96f59692013-02-16 03:13:36 +000020class GCCConfig(object):
21 def __init__(self, githash):
22 self.githash = githash
23
24
25class ToolchainConfig:
26 def __init__(self, gcc_config=None, binutils_config=None):
27 self.gcc_config = gcc_config
28
29
30class ChromeOSCheckout(object):
31 def __init__(self, board, chromeos_root):
32 self._board = board
33 self._chromeos_root = chromeos_root
34 self._ce = command_executer.GetCommandExecuter()
35 self._l = logger.GetLogger()
cmtice56fb7162014-06-18 11:32:15 -070036 self._build_num = None
asharif96f59692013-02-16 03:13:36 +000037
asharif3e38de02013-02-19 19:34:59 +000038 def _DeleteChroot(self):
asharif87414272013-02-19 19:58:45 +000039 command = "cd %s; cros_sdk --delete" % self._chromeos_root
asharif3e38de02013-02-19 19:34:59 +000040 return self._ce.RunCommand(command)
41
asharif67973582013-02-19 20:19:40 +000042 def _DeleteCcahe(self):
43 # crosbug.com/34956
44 command = "sudo rm -rf %s" % os.path.join(self._chromeos_root, ".cache")
45 return self._ce.RunCommand(command)
46
cmtice56fb7162014-06-18 11:32:15 -070047 def _GetBuildNumber(self):
48 """ This function assumes a ChromeOS image has been built in the chroot.
49 It translates the 'latest' symlink in the
50 <chroot>/src/build/images/<board> directory, to find the actual
51 ChromeOS build number for the image that was built. For example, if
52 src/build/image/lumpy/latest -> R37-5982.0.2014_06_23_0454-a1, then
53 This function would parse it out and assign 'R37-5982' to self._build_num.
54 This is used to determine the official, vanilla build to use for
55 comparison tests.
56 """
57 # Get the path to 'latest'
58 sym_path = os.path.join (misc.GetImageDir(self._chromeos_root,
59 self._board),
60 "latest")
61 # Translate the symlink to its 'real' path.
62 real_path = os.path.realpath(sym_path)
63 # Break up the path and get the last piece
64 # (e.g. 'R37-5982.0.2014_06_23_0454-a1"
65 path_pieces = real_path.split("/")
66 last_piece = path_pieces[-1]
67 # Break this piece into the image number + other pieces, and get the
68 # image number [ 'R37-5982', '0', '2014_06_23_0454-a1']
69 image_parts = last_piece.split(".")
70 self._build_num = image_parts[0]
71
asharif96f59692013-02-16 03:13:36 +000072 def _BuildAndImage(self, label=""):
73 if (not label or
74 not misc.DoesLabelExist(self._chromeos_root, self._board, label)):
75 build_chromeos_args = [build_chromeos.__file__,
76 "--chromeos_root=%s" % self._chromeos_root,
77 "--board=%s" % self._board,
78 "--rebuild"]
asharife6b72fe2013-02-19 19:58:18 +000079 if self._public:
80 build_chromeos_args.append("--env=USE=-chrome_internal")
cmtice56fb7162014-06-18 11:32:15 -070081
cmtice23130bd2014-07-15 11:19:29 -070082 if self._board in AFDO_BOARDS:
83 build_chromeos_args.append("--env=USE=afdo_use")
84
asharif96f59692013-02-16 03:13:36 +000085 ret = build_chromeos.Main(build_chromeos_args)
cmtice7f3190b2015-05-22 14:14:51 -070086 if ret != 0:
87 raise RuntimeError("Couldn't build ChromeOS!")
cmtice56fb7162014-06-18 11:32:15 -070088
89 if not self._build_num:
90 self._GetBuildNumber()
91 # Check to see if we need to create the symbolic link for the vanilla
92 # image, and do so if appropriate.
93 if not misc.DoesLabelExist(self._chromeos_root, self._board, "vanilla"):
94 build_name = "%s-release/%s.0.0" % (self._board, self._build_num)
95 full_vanilla_path = os.path.join (os.getcwd(), self._chromeos_root,
96 'chroot/tmp', build_name)
97 misc.LabelLatestImage(self._chromeos_root, self._board, label,
98 full_vanilla_path)
99 else:
asharif96f59692013-02-16 03:13:36 +0000100 misc.LabelLatestImage(self._chromeos_root, self._board, label)
101 return label
102
cmtice56fb7162014-06-18 11:32:15 -0700103 def _SetupBoard(self, env_dict, usepkg_flag, clobber_flag):
asharif96f59692013-02-16 03:13:36 +0000104 env_string = misc.GetEnvStringFromDict(env_dict)
105 command = ("%s %s" %
106 (env_string,
107 misc.GetSetupBoardCommand(self._board,
cmtice56fb7162014-06-18 11:32:15 -0700108 usepkg=usepkg_flag,
109 force=clobber_flag)))
asharif96f59692013-02-16 03:13:36 +0000110 ret = self._ce.ChrootRunCommand(self._chromeos_root,
111 command)
cmtice56fb7162014-06-18 11:32:15 -0700112 error_str = "Could not setup board: '%s'" % command
113 assert ret == 0, error_str
asharif96f59692013-02-16 03:13:36 +0000114
115 def _UnInstallToolchain(self):
116 command = ("sudo CLEAN_DELAY=0 emerge -C cross-%s/gcc" %
117 misc.GetCtargetFromBoard(self._board,
118 self._chromeos_root))
119 ret = self._ce.ChrootRunCommand(self._chromeos_root,
120 command)
cmtice7f3190b2015-05-22 14:14:51 -0700121 if ret != 0:
122 raise RuntimeError("Couldn't uninstall the toolchain!")
asharif96f59692013-02-16 03:13:36 +0000123
124 def _CheckoutChromeOS(self):
125 # TODO(asharif): Setup a fixed ChromeOS version (quarterly snapshot).
126 if not os.path.exists(self._chromeos_root):
127 setup_chromeos_args = [setup_chromeos.__file__,
Caroline Ticec35909e2013-10-02 17:13:13 -0700128 "--dir=%s" % self._chromeos_root]
asharife6b72fe2013-02-19 19:58:18 +0000129 if self._public:
130 setup_chromeos_args.append("--public")
asharif5fe40e22013-02-19 19:58:50 +0000131 ret = setup_chromeos.Main(setup_chromeos_args)
cmtice7f3190b2015-05-22 14:14:51 -0700132 if ret != 0:
133 raise RuntimeError("Couldn't run setup_chromeos!")
asharif96f59692013-02-16 03:13:36 +0000134
Caroline Ticec35909e2013-10-02 17:13:13 -0700135
asharif96f59692013-02-16 03:13:36 +0000136 def _BuildToolchain(self, config):
cmtice56fb7162014-06-18 11:32:15 -0700137 # Call setup_board for basic, vanilla setup.
138 self._SetupBoard({}, usepkg_flag=True, clobber_flag=False)
139 # Now uninstall the vanilla compiler and setup/build our custom
140 # compiler.
asharif96f59692013-02-16 03:13:36 +0000141 self._UnInstallToolchain()
cmtice56fb7162014-06-18 11:32:15 -0700142 envdict = {"USE": "git_gcc",
143 "GCC_GITHASH": config.gcc_config.githash,
144 "EMERGE_DEFAULT_OPTS": "--exclude=gcc"}
145 self._SetupBoard(envdict, usepkg_flag=False, clobber_flag=False)
asharif96f59692013-02-16 03:13:36 +0000146
147
148class ToolchainComparator(ChromeOSCheckout):
Han Shen36413122015-08-28 11:05:40 -0700149 def __init__(self, board, remotes, configs, clean,
150 public, force_mismatch, schedv2=False):
asharif96f59692013-02-16 03:13:36 +0000151 self._board = board
152 self._remotes = remotes
153 self._chromeos_root = "chromeos"
154 self._configs = configs
asharif3e38de02013-02-19 19:34:59 +0000155 self._clean = clean
asharife6b72fe2013-02-19 19:58:18 +0000156 self._public = public
asharif58a8c9f2013-02-19 20:42:43 +0000157 self._force_mismatch = force_mismatch
asharif96f59692013-02-16 03:13:36 +0000158 self._ce = command_executer.GetCommandExecuter()
159 self._l = logger.GetLogger()
cmtice7f3190b2015-05-22 14:14:51 -0700160 timestamp = datetime.datetime.strftime(datetime.datetime.now(),
161 "%Y-%m-%d_%H:%M:%S")
162 self._reports_dir = os.path.join(
163 os.path.expanduser("~/nightly_test_reports"),
164 "%s.%s" % (timestamp, board),
165 )
Han Shen36413122015-08-28 11:05:40 -0700166 self._schedv2 = schedv2
asharif96f59692013-02-16 03:13:36 +0000167 ChromeOSCheckout.__init__(self, board, self._chromeos_root)
168
cmticea6255d02014-01-10 10:27:22 -0800169
170 def _FinishSetup(self):
171 # Get correct .boto file
172 current_dir = os.getcwd()
173 src = "/home/mobiletc-prebuild/.boto"
174 dest = os.path.join(current_dir, self._chromeos_root,
175 "src/private-overlays/chromeos-overlay/"
176 "googlestorage_account.boto")
177 # Copy the file to the correct place
178 copy_cmd = "cp %s %s" % (src, dest)
179 retval = self._ce.RunCommand(copy_cmd)
cmtice7f3190b2015-05-22 14:14:51 -0700180 if retval != 0:
181 raise RuntimeError("Couldn't copy .boto file for google storage.")
cmticea6255d02014-01-10 10:27:22 -0800182
183 # Fix protections on ssh key
184 command = ("chmod 600 /var/cache/chromeos-cache/distfiles/target"
185 "/chrome-src-internal/src/third_party/chromite/ssh_keys"
186 "/testing_rsa")
187 retval = self._ce.ChrootRunCommand(self._chromeos_root, command)
cmtice7f3190b2015-05-22 14:14:51 -0700188 if retval != 0:
189 raise RuntimeError("chmod for testing_rsa failed")
cmticea6255d02014-01-10 10:27:22 -0800190
asharif96f59692013-02-16 03:13:36 +0000191 def _TestLabels(self, labels):
192 experiment_file = "toolchain_experiment.txt"
asharif58a8c9f2013-02-19 20:42:43 +0000193 image_args = ""
194 if self._force_mismatch:
asharif0b5d5c82013-02-19 20:42:56 +0000195 image_args = "--force-mismatch"
asharif96f59692013-02-16 03:13:36 +0000196 experiment_header = """
197 board: %s
198 remote: %s
cmticed1f03b82015-06-30 15:19:23 -0700199 retries: 1
asharif96f59692013-02-16 03:13:36 +0000200 """ % (self._board, self._remotes)
201 experiment_tests = """
cmtice0c84ea72015-06-25 14:22:36 -0700202 benchmark: all_toolchain_perf {
cmtice04403882013-11-04 16:38:37 -0500203 suite: telemetry_Crosperf
cmtice6de7f8f2014-03-14 14:08:21 -0700204 iterations: 3
asharif96f59692013-02-16 03:13:36 +0000205 }
206 """
207 with open(experiment_file, "w") as f:
208 print >>f, experiment_header
209 print >>f, experiment_tests
210 for label in labels:
211 # TODO(asharif): Fix crosperf so it accepts labels with symbols
212 crosperf_label = label
213 crosperf_label = crosperf_label.replace("-", "minus")
214 crosperf_label = crosperf_label.replace("+", "plus")
asharife4a5a8f2013-02-19 20:19:33 +0000215 crosperf_label = crosperf_label.replace(".", "")
cmtice56fb7162014-06-18 11:32:15 -0700216
217 # Use the official build instead of building vanilla ourselves.
218 if label == "vanilla":
219 build_name = '%s-release/%s.0.0' % (self._board, self._build_num)
220
221 # Now add 'official build' to test file.
222 official_image = """
223 official_image {
224 chromeos_root: %s
225 build: %s
226 }
227 """ % (self._chromeos_root, build_name)
228 print >>f, official_image
229
cmtice94bc4702014-05-29 16:29:04 -0700230 else:
cmtice56fb7162014-06-18 11:32:15 -0700231 experiment_image = """
232 %s {
233 chromeos_image: %s
234 image_args: %s
235 }
236 """ % (crosperf_label,
237 os.path.join(misc.GetImageDir(self._chromeos_root,
238 self._board),
239 label, "chromiumos_test_image.bin"),
240 image_args)
241 print >>f, experiment_image
242
asharif96f59692013-02-16 03:13:36 +0000243 crosperf = os.path.join(os.path.dirname(__file__),
244 "crosperf",
245 "crosperf")
Han Shen36413122015-08-28 11:05:40 -0700246 schedv2_opts = '--schedv2 --logging_level=verbose' if self._schedv2 else ''
247 command = ("{crosperf} --no_email=True --results_dir={r_dir} "
248 "{schedv2_opts} {exp_file}").format(
249 crosperf=crosperf,
250 r_dir=self._reports_dir,
251 schedv2_opts=schedv2_opts,
252 exp_file=experiment_file)
cmticeaa700b02015-06-12 13:26:47 -0700253
asharif96f59692013-02-16 03:13:36 +0000254 ret = self._ce.RunCommand(command)
cmtice7f3190b2015-05-22 14:14:51 -0700255 if ret != 0:
256 raise RuntimeError("Couldn't run crosperf!")
257 return
cmtice56fb7162014-06-18 11:32:15 -0700258
259
260 def _CopyWeeklyReportFiles(self, labels):
261 """Create tar files of the custom and official images and copy them
262 to the weekly reports directory, so they exist when the weekly report
263 gets generated. IMPORTANT NOTE: This function must run *after*
264 crosperf has been run; otherwise the vanilla images will not be there.
265 """
266 images_path = os.path.join(os.path.realpath(self._chromeos_root),
267 "src/build/images", self._board)
268 weekday = time.strftime("%a")
269 data_dir = os.path.join(WEEKLY_REPORTS_ROOT, self._board)
270 dest_dir = os.path.join (data_dir, weekday)
271 if not os.path.exists(dest_dir):
272 os.makedirs(dest_dir)
cmtice4536ef62014-07-08 11:17:21 -0700273 # Make sure dest_dir is empty (clean out last week's data).
274 cmd = "cd %s; rm -Rf %s_*_image*" % (dest_dir, weekday)
275 self._ce.RunCommand(cmd)
276 # Now create new tar files and copy them over.
cmtice56fb7162014-06-18 11:32:15 -0700277 for l in labels:
278 test_path = os.path.join(images_path, l)
279 if os.path.exists(test_path):
280 if l != "vanilla":
281 label_name = "test"
282 else:
283 label_name = "vanilla"
284 tar_file_name = "%s_%s_image.tar" % (weekday, label_name)
Han Shenfe054f12015-02-18 15:00:13 -0800285 cmd = ("cd %s; tar -cvf %s %s/chromiumos_test_image.bin; "
286 "cp %s %s/.") % (images_path,
287 tar_file_name,
288 l, tar_file_name,
289 dest_dir)
cmtice56fb7162014-06-18 11:32:15 -0700290 tar_ret = self._ce.RunCommand(cmd)
cmtice7f3190b2015-05-22 14:14:51 -0700291 if tar_ret != 0:
cmtice56fb7162014-06-18 11:32:15 -0700292 self._l.LogOutput("Error while creating/copying test tar file(%s)."
293 % tar_file_name)
294
cmtice7f3190b2015-05-22 14:14:51 -0700295 def _SendEmail(self):
296 """Find email msesage generated by crosperf and send it."""
297 filename = os.path.join(self._reports_dir, "msg_body.html")
298 if (os.path.exists(filename) and
299 os.path.exists(os.path.expanduser(MAIL_PROGRAM))):
cmtice0495c712015-05-28 15:21:07 -0700300 command = ('cat %s | %s -s "Nightly test results, %s" -team -html'
301 % (filename, MAIL_PROGRAM, self._board))
cmtice7f3190b2015-05-22 14:14:51 -0700302 self._ce.RunCommand(command)
asharif96f59692013-02-16 03:13:36 +0000303
304 def DoAll(self):
305 self._CheckoutChromeOS()
asharif96f59692013-02-16 03:13:36 +0000306 labels = []
cmtice56fb7162014-06-18 11:32:15 -0700307 labels.append("vanilla")
asharif96f59692013-02-16 03:13:36 +0000308 for config in self._configs:
309 label = misc.GetFilenameFromString(config.gcc_config.githash)
310 if (not misc.DoesLabelExist(self._chromeos_root,
311 self._board,
312 label)):
313 self._BuildToolchain(config)
314 label = self._BuildAndImage(label)
315 labels.append(label)
cmticea6255d02014-01-10 10:27:22 -0800316 self._FinishSetup()
cmticeb4588092015-05-27 08:07:50 -0700317 self._TestLabels(labels)
cmtice7f3190b2015-05-22 14:14:51 -0700318 self._SendEmail()
319 # Only try to copy the image files if the test runs ran successfully.
320 self._CopyWeeklyReportFiles(labels)
asharif3e38de02013-02-19 19:34:59 +0000321 if self._clean:
322 ret = self._DeleteChroot()
cmtice7f3190b2015-05-22 14:14:51 -0700323 if ret != 0:
324 return ret
asharif67973582013-02-19 20:19:40 +0000325 ret = self._DeleteCcahe()
cmtice7f3190b2015-05-22 14:14:51 -0700326 if ret != 0:
327 return ret
asharif96f59692013-02-16 03:13:36 +0000328 return 0
329
330
331def Main(argv):
332 """The main function."""
333 # Common initializations
334### command_executer.InitCommandExecuter(True)
335 command_executer.InitCommandExecuter()
336 parser = optparse.OptionParser()
337 parser.add_option("--remote",
338 dest="remote",
339 help="Remote machines to run tests on.")
340 parser.add_option("--board",
341 dest="board",
342 default="x86-zgb",
343 help="The target board.")
344 parser.add_option("--githashes",
345 dest="githashes",
346 default="master",
347 help="The gcc githashes to test.")
asharif3e38de02013-02-19 19:34:59 +0000348 parser.add_option("--clean",
349 dest="clean",
350 default=False,
351 action="store_true",
352 help="Clean the chroot after testing.")
asharife6b72fe2013-02-19 19:58:18 +0000353 parser.add_option("--public",
354 dest="public",
355 default=False,
356 action="store_true",
357 help="Use the public checkout/build.")
asharif58a8c9f2013-02-19 20:42:43 +0000358 parser.add_option("--force-mismatch",
359 dest="force_mismatch",
360 default="",
361 help="Force the image regardless of board mismatch")
Han Shen36413122015-08-28 11:05:40 -0700362 parser.add_option("--schedv2",
363 dest="schedv2",
364 action="store_true",
365 default=False,
366 help="Pass --schedv2 to crosperf.")
asharif96f59692013-02-16 03:13:36 +0000367 options, _ = parser.parse_args(argv)
368 if not options.board:
369 print "Please give a board."
370 return 1
371 if not options.remote:
372 print "Please give at least one remote machine."
373 return 1
374 toolchain_configs = []
375 for githash in options.githashes.split(","):
376 gcc_config = GCCConfig(githash=githash)
377 toolchain_config = ToolchainConfig(gcc_config=gcc_config)
378 toolchain_configs.append(toolchain_config)
asharif3e38de02013-02-19 19:34:59 +0000379 fc = ToolchainComparator(options.board, options.remote, toolchain_configs,
asharif58a8c9f2013-02-19 20:42:43 +0000380 options.clean, options.public,
Han Shen36413122015-08-28 11:05:40 -0700381 options.force_mismatch,
382 options.schedv2)
asharif96f59692013-02-16 03:13:36 +0000383 return fc.DoAll()
384
385
386if __name__ == "__main__":
387 retval = Main(sys.argv)
388 sys.exit(retval)