blob: ceb392805f5b40a571a0232c88d4e72de301f198 [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
Caroline Ticeebbc3da2015-09-03 10:27:20 -070016CROSTC_ROOT = "/usr/local/google/crostc"
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"
Caroline Ticeebbc3da2015-09-03 10:27:20 -070019WEEKLY_REPORTS_ROOT = os.path.join(CROSTC_ROOT, "weekly_test_data")
20PENDING_ARCHIVES_DIR = os.path.join(CROSTC_ROOT, "pending_archives")
21NIGHTLY_TESTS_DIR = os.path.join(CROSTC_ROOT, "nightly_test_reports")
cmtice94bc4702014-05-29 16:29:04 -070022
asharif96f59692013-02-16 03:13:36 +000023class GCCConfig(object):
24 def __init__(self, githash):
25 self.githash = githash
26
27
28class ToolchainConfig:
29 def __init__(self, gcc_config=None, binutils_config=None):
30 self.gcc_config = gcc_config
31
32
33class ChromeOSCheckout(object):
34 def __init__(self, board, chromeos_root):
35 self._board = board
36 self._chromeos_root = chromeos_root
37 self._ce = command_executer.GetCommandExecuter()
38 self._l = logger.GetLogger()
cmtice56fb7162014-06-18 11:32:15 -070039 self._build_num = None
asharif96f59692013-02-16 03:13:36 +000040
asharif3e38de02013-02-19 19:34:59 +000041 def _DeleteChroot(self):
asharif87414272013-02-19 19:58:45 +000042 command = "cd %s; cros_sdk --delete" % self._chromeos_root
asharif3e38de02013-02-19 19:34:59 +000043 return self._ce.RunCommand(command)
44
asharif67973582013-02-19 20:19:40 +000045 def _DeleteCcahe(self):
46 # crosbug.com/34956
47 command = "sudo rm -rf %s" % os.path.join(self._chromeos_root, ".cache")
48 return self._ce.RunCommand(command)
49
cmtice56fb7162014-06-18 11:32:15 -070050 def _GetBuildNumber(self):
51 """ This function assumes a ChromeOS image has been built in the chroot.
52 It translates the 'latest' symlink in the
53 <chroot>/src/build/images/<board> directory, to find the actual
54 ChromeOS build number for the image that was built. For example, if
55 src/build/image/lumpy/latest -> R37-5982.0.2014_06_23_0454-a1, then
56 This function would parse it out and assign 'R37-5982' to self._build_num.
57 This is used to determine the official, vanilla build to use for
58 comparison tests.
59 """
60 # Get the path to 'latest'
61 sym_path = os.path.join (misc.GetImageDir(self._chromeos_root,
62 self._board),
63 "latest")
64 # Translate the symlink to its 'real' path.
65 real_path = os.path.realpath(sym_path)
66 # Break up the path and get the last piece
67 # (e.g. 'R37-5982.0.2014_06_23_0454-a1"
68 path_pieces = real_path.split("/")
69 last_piece = path_pieces[-1]
70 # Break this piece into the image number + other pieces, and get the
71 # image number [ 'R37-5982', '0', '2014_06_23_0454-a1']
72 image_parts = last_piece.split(".")
73 self._build_num = image_parts[0]
74
asharif96f59692013-02-16 03:13:36 +000075 def _BuildAndImage(self, label=""):
76 if (not label or
77 not misc.DoesLabelExist(self._chromeos_root, self._board, label)):
78 build_chromeos_args = [build_chromeos.__file__,
79 "--chromeos_root=%s" % self._chromeos_root,
80 "--board=%s" % self._board,
81 "--rebuild"]
asharife6b72fe2013-02-19 19:58:18 +000082 if self._public:
83 build_chromeos_args.append("--env=USE=-chrome_internal")
cmtice56fb7162014-06-18 11:32:15 -070084
cmtice23130bd2014-07-15 11:19:29 -070085 if self._board in AFDO_BOARDS:
86 build_chromeos_args.append("--env=USE=afdo_use")
87
asharif96f59692013-02-16 03:13:36 +000088 ret = build_chromeos.Main(build_chromeos_args)
cmtice7f3190b2015-05-22 14:14:51 -070089 if ret != 0:
90 raise RuntimeError("Couldn't build ChromeOS!")
cmtice56fb7162014-06-18 11:32:15 -070091
92 if not self._build_num:
93 self._GetBuildNumber()
94 # Check to see if we need to create the symbolic link for the vanilla
95 # image, and do so if appropriate.
96 if not misc.DoesLabelExist(self._chromeos_root, self._board, "vanilla"):
97 build_name = "%s-release/%s.0.0" % (self._board, self._build_num)
98 full_vanilla_path = os.path.join (os.getcwd(), self._chromeos_root,
99 'chroot/tmp', build_name)
100 misc.LabelLatestImage(self._chromeos_root, self._board, label,
101 full_vanilla_path)
102 else:
asharif96f59692013-02-16 03:13:36 +0000103 misc.LabelLatestImage(self._chromeos_root, self._board, label)
104 return label
105
cmtice56fb7162014-06-18 11:32:15 -0700106 def _SetupBoard(self, env_dict, usepkg_flag, clobber_flag):
asharif96f59692013-02-16 03:13:36 +0000107 env_string = misc.GetEnvStringFromDict(env_dict)
108 command = ("%s %s" %
109 (env_string,
110 misc.GetSetupBoardCommand(self._board,
cmtice56fb7162014-06-18 11:32:15 -0700111 usepkg=usepkg_flag,
112 force=clobber_flag)))
asharif96f59692013-02-16 03:13:36 +0000113 ret = self._ce.ChrootRunCommand(self._chromeos_root,
114 command)
cmtice56fb7162014-06-18 11:32:15 -0700115 error_str = "Could not setup board: '%s'" % command
116 assert ret == 0, error_str
asharif96f59692013-02-16 03:13:36 +0000117
118 def _UnInstallToolchain(self):
119 command = ("sudo CLEAN_DELAY=0 emerge -C cross-%s/gcc" %
120 misc.GetCtargetFromBoard(self._board,
121 self._chromeos_root))
122 ret = self._ce.ChrootRunCommand(self._chromeos_root,
123 command)
cmtice7f3190b2015-05-22 14:14:51 -0700124 if ret != 0:
125 raise RuntimeError("Couldn't uninstall the toolchain!")
asharif96f59692013-02-16 03:13:36 +0000126
127 def _CheckoutChromeOS(self):
128 # TODO(asharif): Setup a fixed ChromeOS version (quarterly snapshot).
129 if not os.path.exists(self._chromeos_root):
130 setup_chromeos_args = [setup_chromeos.__file__,
Caroline Ticec35909e2013-10-02 17:13:13 -0700131 "--dir=%s" % self._chromeos_root]
asharife6b72fe2013-02-19 19:58:18 +0000132 if self._public:
133 setup_chromeos_args.append("--public")
asharif5fe40e22013-02-19 19:58:50 +0000134 ret = setup_chromeos.Main(setup_chromeos_args)
cmtice7f3190b2015-05-22 14:14:51 -0700135 if ret != 0:
136 raise RuntimeError("Couldn't run setup_chromeos!")
asharif96f59692013-02-16 03:13:36 +0000137
Caroline Ticec35909e2013-10-02 17:13:13 -0700138
asharif96f59692013-02-16 03:13:36 +0000139 def _BuildToolchain(self, config):
cmtice56fb7162014-06-18 11:32:15 -0700140 # Call setup_board for basic, vanilla setup.
141 self._SetupBoard({}, usepkg_flag=True, clobber_flag=False)
142 # Now uninstall the vanilla compiler and setup/build our custom
143 # compiler.
asharif96f59692013-02-16 03:13:36 +0000144 self._UnInstallToolchain()
cmtice56fb7162014-06-18 11:32:15 -0700145 envdict = {"USE": "git_gcc",
146 "GCC_GITHASH": config.gcc_config.githash,
147 "EMERGE_DEFAULT_OPTS": "--exclude=gcc"}
148 self._SetupBoard(envdict, usepkg_flag=False, clobber_flag=False)
asharif96f59692013-02-16 03:13:36 +0000149
150
151class ToolchainComparator(ChromeOSCheckout):
Han Shen36413122015-08-28 11:05:40 -0700152 def __init__(self, board, remotes, configs, clean,
Han Shen43494292015-09-14 10:26:40 -0700153 public, force_mismatch, noschedv2=False):
asharif96f59692013-02-16 03:13:36 +0000154 self._board = board
155 self._remotes = remotes
156 self._chromeos_root = "chromeos"
157 self._configs = configs
asharif3e38de02013-02-19 19:34:59 +0000158 self._clean = clean
asharife6b72fe2013-02-19 19:58:18 +0000159 self._public = public
asharif58a8c9f2013-02-19 20:42:43 +0000160 self._force_mismatch = force_mismatch
asharif96f59692013-02-16 03:13:36 +0000161 self._ce = command_executer.GetCommandExecuter()
162 self._l = logger.GetLogger()
cmtice7f3190b2015-05-22 14:14:51 -0700163 timestamp = datetime.datetime.strftime(datetime.datetime.now(),
164 "%Y-%m-%d_%H:%M:%S")
Caroline Ticeebbc3da2015-09-03 10:27:20 -0700165 self._reports_dir = os.path.join(NIGHTLY_TESTS_DIR,
cmtice7f3190b2015-05-22 14:14:51 -0700166 "%s.%s" % (timestamp, board),
167 )
Han Shen43494292015-09-14 10:26:40 -0700168 self._noschedv2 = noschedv2
asharif96f59692013-02-16 03:13:36 +0000169 ChromeOSCheckout.__init__(self, board, self._chromeos_root)
170
cmticea6255d02014-01-10 10:27:22 -0800171
172 def _FinishSetup(self):
173 # Get correct .boto file
174 current_dir = os.getcwd()
Caroline Ticeebbc3da2015-09-03 10:27:20 -0700175 src = "/usr/local/google/home/mobiletc-prebuild/.boto"
cmticea6255d02014-01-10 10:27:22 -0800176 dest = os.path.join(current_dir, self._chromeos_root,
177 "src/private-overlays/chromeos-overlay/"
178 "googlestorage_account.boto")
179 # Copy the file to the correct place
180 copy_cmd = "cp %s %s" % (src, dest)
181 retval = self._ce.RunCommand(copy_cmd)
cmtice7f3190b2015-05-22 14:14:51 -0700182 if retval != 0:
183 raise RuntimeError("Couldn't copy .boto file for google storage.")
cmticea6255d02014-01-10 10:27:22 -0800184
185 # Fix protections on ssh key
186 command = ("chmod 600 /var/cache/chromeos-cache/distfiles/target"
187 "/chrome-src-internal/src/third_party/chromite/ssh_keys"
188 "/testing_rsa")
189 retval = self._ce.ChrootRunCommand(self._chromeos_root, command)
cmtice7f3190b2015-05-22 14:14:51 -0700190 if retval != 0:
191 raise RuntimeError("chmod for testing_rsa failed")
cmticea6255d02014-01-10 10:27:22 -0800192
asharif96f59692013-02-16 03:13:36 +0000193 def _TestLabels(self, labels):
194 experiment_file = "toolchain_experiment.txt"
asharif58a8c9f2013-02-19 20:42:43 +0000195 image_args = ""
196 if self._force_mismatch:
asharif0b5d5c82013-02-19 20:42:56 +0000197 image_args = "--force-mismatch"
asharif96f59692013-02-16 03:13:36 +0000198 experiment_header = """
199 board: %s
200 remote: %s
cmticed1f03b82015-06-30 15:19:23 -0700201 retries: 1
asharif96f59692013-02-16 03:13:36 +0000202 """ % (self._board, self._remotes)
203 experiment_tests = """
cmtice0c84ea72015-06-25 14:22:36 -0700204 benchmark: all_toolchain_perf {
cmtice04403882013-11-04 16:38:37 -0500205 suite: telemetry_Crosperf
cmtice6de7f8f2014-03-14 14:08:21 -0700206 iterations: 3
asharif96f59692013-02-16 03:13:36 +0000207 }
208 """
209 with open(experiment_file, "w") as f:
210 print >>f, experiment_header
211 print >>f, experiment_tests
212 for label in labels:
213 # TODO(asharif): Fix crosperf so it accepts labels with symbols
214 crosperf_label = label
215 crosperf_label = crosperf_label.replace("-", "minus")
216 crosperf_label = crosperf_label.replace("+", "plus")
asharife4a5a8f2013-02-19 20:19:33 +0000217 crosperf_label = crosperf_label.replace(".", "")
cmtice56fb7162014-06-18 11:32:15 -0700218
219 # Use the official build instead of building vanilla ourselves.
220 if label == "vanilla":
221 build_name = '%s-release/%s.0.0' % (self._board, self._build_num)
222
223 # Now add 'official build' to test file.
224 official_image = """
225 official_image {
226 chromeos_root: %s
227 build: %s
228 }
229 """ % (self._chromeos_root, build_name)
230 print >>f, official_image
231
cmtice94bc4702014-05-29 16:29:04 -0700232 else:
cmtice56fb7162014-06-18 11:32:15 -0700233 experiment_image = """
234 %s {
235 chromeos_image: %s
236 image_args: %s
237 }
238 """ % (crosperf_label,
239 os.path.join(misc.GetImageDir(self._chromeos_root,
240 self._board),
241 label, "chromiumos_test_image.bin"),
242 image_args)
243 print >>f, experiment_image
244
asharif96f59692013-02-16 03:13:36 +0000245 crosperf = os.path.join(os.path.dirname(__file__),
246 "crosperf",
247 "crosperf")
Han Shen43494292015-09-14 10:26:40 -0700248 noschedv2_opts = '--noschedv2' if self._noschedv2 else ''
Han Shen36413122015-08-28 11:05:40 -0700249 command = ("{crosperf} --no_email=True --results_dir={r_dir} "
Han Shen43494292015-09-14 10:26:40 -0700250 "--json_report=True {noschedv2_opts} {exp_file}").format(
Han Shen36413122015-08-28 11:05:40 -0700251 crosperf=crosperf,
252 r_dir=self._reports_dir,
Han Shen43494292015-09-14 10:26:40 -0700253 noschedv2_opts=noschedv2_opts,
Han Shen36413122015-08-28 11:05:40 -0700254 exp_file=experiment_file)
cmticeaa700b02015-06-12 13:26:47 -0700255
asharif96f59692013-02-16 03:13:36 +0000256 ret = self._ce.RunCommand(command)
cmtice7f3190b2015-05-22 14:14:51 -0700257 if ret != 0:
258 raise RuntimeError("Couldn't run crosperf!")
Caroline Ticeebbc3da2015-09-03 10:27:20 -0700259 else:
260 # Copy json report to pending archives directory.
261 command = "cp %s/*.json %s/." % (self._reports_dir, PENDING_ARCHIVES_DIR)
262 ret = self._ce.RunCommand(command)
cmtice7f3190b2015-05-22 14:14:51 -0700263 return
cmtice56fb7162014-06-18 11:32:15 -0700264
265
266 def _CopyWeeklyReportFiles(self, labels):
267 """Create tar files of the custom and official images and copy them
268 to the weekly reports directory, so they exist when the weekly report
269 gets generated. IMPORTANT NOTE: This function must run *after*
270 crosperf has been run; otherwise the vanilla images will not be there.
271 """
272 images_path = os.path.join(os.path.realpath(self._chromeos_root),
273 "src/build/images", self._board)
274 weekday = time.strftime("%a")
275 data_dir = os.path.join(WEEKLY_REPORTS_ROOT, self._board)
276 dest_dir = os.path.join (data_dir, weekday)
277 if not os.path.exists(dest_dir):
278 os.makedirs(dest_dir)
cmtice4536ef62014-07-08 11:17:21 -0700279 # Make sure dest_dir is empty (clean out last week's data).
280 cmd = "cd %s; rm -Rf %s_*_image*" % (dest_dir, weekday)
281 self._ce.RunCommand(cmd)
282 # Now create new tar files and copy them over.
cmtice56fb7162014-06-18 11:32:15 -0700283 for l in labels:
284 test_path = os.path.join(images_path, l)
285 if os.path.exists(test_path):
286 if l != "vanilla":
287 label_name = "test"
288 else:
289 label_name = "vanilla"
290 tar_file_name = "%s_%s_image.tar" % (weekday, label_name)
Han Shenfe054f12015-02-18 15:00:13 -0800291 cmd = ("cd %s; tar -cvf %s %s/chromiumos_test_image.bin; "
292 "cp %s %s/.") % (images_path,
293 tar_file_name,
294 l, tar_file_name,
295 dest_dir)
cmtice56fb7162014-06-18 11:32:15 -0700296 tar_ret = self._ce.RunCommand(cmd)
cmtice7f3190b2015-05-22 14:14:51 -0700297 if tar_ret != 0:
cmtice56fb7162014-06-18 11:32:15 -0700298 self._l.LogOutput("Error while creating/copying test tar file(%s)."
299 % tar_file_name)
300
cmtice7f3190b2015-05-22 14:14:51 -0700301 def _SendEmail(self):
302 """Find email msesage generated by crosperf and send it."""
303 filename = os.path.join(self._reports_dir, "msg_body.html")
304 if (os.path.exists(filename) and
305 os.path.exists(os.path.expanduser(MAIL_PROGRAM))):
cmtice0495c712015-05-28 15:21:07 -0700306 command = ('cat %s | %s -s "Nightly test results, %s" -team -html'
307 % (filename, MAIL_PROGRAM, self._board))
cmtice7f3190b2015-05-22 14:14:51 -0700308 self._ce.RunCommand(command)
asharif96f59692013-02-16 03:13:36 +0000309
310 def DoAll(self):
311 self._CheckoutChromeOS()
asharif96f59692013-02-16 03:13:36 +0000312 labels = []
cmtice56fb7162014-06-18 11:32:15 -0700313 labels.append("vanilla")
asharif96f59692013-02-16 03:13:36 +0000314 for config in self._configs:
315 label = misc.GetFilenameFromString(config.gcc_config.githash)
316 if (not misc.DoesLabelExist(self._chromeos_root,
317 self._board,
318 label)):
319 self._BuildToolchain(config)
320 label = self._BuildAndImage(label)
321 labels.append(label)
cmticea6255d02014-01-10 10:27:22 -0800322 self._FinishSetup()
cmticeb4588092015-05-27 08:07:50 -0700323 self._TestLabels(labels)
cmtice7f3190b2015-05-22 14:14:51 -0700324 self._SendEmail()
325 # Only try to copy the image files if the test runs ran successfully.
326 self._CopyWeeklyReportFiles(labels)
asharif3e38de02013-02-19 19:34:59 +0000327 if self._clean:
328 ret = self._DeleteChroot()
cmtice7f3190b2015-05-22 14:14:51 -0700329 if ret != 0:
330 return ret
asharif67973582013-02-19 20:19:40 +0000331 ret = self._DeleteCcahe()
cmtice7f3190b2015-05-22 14:14:51 -0700332 if ret != 0:
333 return ret
asharif96f59692013-02-16 03:13:36 +0000334 return 0
335
336
337def Main(argv):
338 """The main function."""
339 # Common initializations
340### command_executer.InitCommandExecuter(True)
341 command_executer.InitCommandExecuter()
342 parser = optparse.OptionParser()
343 parser.add_option("--remote",
344 dest="remote",
345 help="Remote machines to run tests on.")
346 parser.add_option("--board",
347 dest="board",
348 default="x86-zgb",
349 help="The target board.")
350 parser.add_option("--githashes",
351 dest="githashes",
352 default="master",
353 help="The gcc githashes to test.")
asharif3e38de02013-02-19 19:34:59 +0000354 parser.add_option("--clean",
355 dest="clean",
356 default=False,
357 action="store_true",
358 help="Clean the chroot after testing.")
asharife6b72fe2013-02-19 19:58:18 +0000359 parser.add_option("--public",
360 dest="public",
361 default=False,
362 action="store_true",
363 help="Use the public checkout/build.")
asharif58a8c9f2013-02-19 20:42:43 +0000364 parser.add_option("--force-mismatch",
365 dest="force_mismatch",
366 default="",
367 help="Force the image regardless of board mismatch")
Han Shen43494292015-09-14 10:26:40 -0700368 parser.add_option("--noschedv2",
369 dest="noschedv2",
Han Shen36413122015-08-28 11:05:40 -0700370 action="store_true",
371 default=False,
Han Shen43494292015-09-14 10:26:40 -0700372 help="Pass --noschedv2 to crosperf.")
asharif96f59692013-02-16 03:13:36 +0000373 options, _ = parser.parse_args(argv)
374 if not options.board:
375 print "Please give a board."
376 return 1
377 if not options.remote:
378 print "Please give at least one remote machine."
379 return 1
380 toolchain_configs = []
381 for githash in options.githashes.split(","):
382 gcc_config = GCCConfig(githash=githash)
383 toolchain_config = ToolchainConfig(gcc_config=gcc_config)
384 toolchain_configs.append(toolchain_config)
asharif3e38de02013-02-19 19:34:59 +0000385 fc = ToolchainComparator(options.board, options.remote, toolchain_configs,
asharif58a8c9f2013-02-19 20:42:43 +0000386 options.clean, options.public,
Han Shen36413122015-08-28 11:05:40 -0700387 options.force_mismatch,
Han Shen43494292015-09-14 10:26:40 -0700388 options.noschedv2)
asharif96f59692013-02-16 03:13:36 +0000389 return fc.DoAll()
390
391
392if __name__ == "__main__":
393 retval = Main(sys.argv)
394 sys.exit(retval)