blob: 0c6f1d827c11597f911d40ad6559b3cd5c0645e1 [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
Caroline Tice80eab982015-11-04 14:03:14 -08007import string
asharif96f59692013-02-16 03:13:36 +00008import sys
9import build_chromeos
10import setup_chromeos
cmtice94bc4702014-05-29 16:29:04 -070011import time
asharif96f59692013-02-16 03:13:36 +000012from utils import command_executer
13from utils import misc
14from utils import logger
15
16
Caroline Ticeebbc3da2015-09-03 10:27:20 -070017CROSTC_ROOT = "/usr/local/google/crostc"
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
Caroline Tice80eab982015-11-04 14:03:14 -080075 def _BuildLabelName(self, config, board):
76 pieces = config.split("/")
77 compiler_version = pieces[-1]
78 label = compiler_version + "_tot_afdo"
79 return label
80
asharif96f59692013-02-16 03:13:36 +000081 def _BuildAndImage(self, label=""):
82 if (not label or
83 not misc.DoesLabelExist(self._chromeos_root, self._board, label)):
84 build_chromeos_args = [build_chromeos.__file__,
85 "--chromeos_root=%s" % self._chromeos_root,
86 "--board=%s" % self._board,
87 "--rebuild"]
asharife6b72fe2013-02-19 19:58:18 +000088 if self._public:
89 build_chromeos_args.append("--env=USE=-chrome_internal")
cmtice56fb7162014-06-18 11:32:15 -070090
asharif96f59692013-02-16 03:13:36 +000091 ret = build_chromeos.Main(build_chromeos_args)
cmtice7f3190b2015-05-22 14:14:51 -070092 if ret != 0:
93 raise RuntimeError("Couldn't build ChromeOS!")
cmtice56fb7162014-06-18 11:32:15 -070094
95 if not self._build_num:
96 self._GetBuildNumber()
97 # Check to see if we need to create the symbolic link for the vanilla
98 # image, and do so if appropriate.
99 if not misc.DoesLabelExist(self._chromeos_root, self._board, "vanilla"):
100 build_name = "%s-release/%s.0.0" % (self._board, self._build_num)
101 full_vanilla_path = os.path.join (os.getcwd(), self._chromeos_root,
102 'chroot/tmp', build_name)
103 misc.LabelLatestImage(self._chromeos_root, self._board, label,
104 full_vanilla_path)
105 else:
asharif96f59692013-02-16 03:13:36 +0000106 misc.LabelLatestImage(self._chromeos_root, self._board, label)
107 return label
108
cmtice56fb7162014-06-18 11:32:15 -0700109 def _SetupBoard(self, env_dict, usepkg_flag, clobber_flag):
asharif96f59692013-02-16 03:13:36 +0000110 env_string = misc.GetEnvStringFromDict(env_dict)
111 command = ("%s %s" %
112 (env_string,
113 misc.GetSetupBoardCommand(self._board,
cmtice56fb7162014-06-18 11:32:15 -0700114 usepkg=usepkg_flag,
115 force=clobber_flag)))
asharif96f59692013-02-16 03:13:36 +0000116 ret = self._ce.ChrootRunCommand(self._chromeos_root,
117 command)
cmtice56fb7162014-06-18 11:32:15 -0700118 error_str = "Could not setup board: '%s'" % command
119 assert ret == 0, error_str
asharif96f59692013-02-16 03:13:36 +0000120
121 def _UnInstallToolchain(self):
122 command = ("sudo CLEAN_DELAY=0 emerge -C cross-%s/gcc" %
123 misc.GetCtargetFromBoard(self._board,
124 self._chromeos_root))
125 ret = self._ce.ChrootRunCommand(self._chromeos_root,
126 command)
cmtice7f3190b2015-05-22 14:14:51 -0700127 if ret != 0:
128 raise RuntimeError("Couldn't uninstall the toolchain!")
asharif96f59692013-02-16 03:13:36 +0000129
130 def _CheckoutChromeOS(self):
131 # TODO(asharif): Setup a fixed ChromeOS version (quarterly snapshot).
132 if not os.path.exists(self._chromeos_root):
133 setup_chromeos_args = [setup_chromeos.__file__,
Caroline Ticec35909e2013-10-02 17:13:13 -0700134 "--dir=%s" % self._chromeos_root]
asharife6b72fe2013-02-19 19:58:18 +0000135 if self._public:
136 setup_chromeos_args.append("--public")
asharif5fe40e22013-02-19 19:58:50 +0000137 ret = setup_chromeos.Main(setup_chromeos_args)
cmtice7f3190b2015-05-22 14:14:51 -0700138 if ret != 0:
139 raise RuntimeError("Couldn't run setup_chromeos!")
asharif96f59692013-02-16 03:13:36 +0000140
Caroline Ticec35909e2013-10-02 17:13:13 -0700141
asharif96f59692013-02-16 03:13:36 +0000142 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()
cmtice56fb7162014-06-18 11:32:15 -0700148 envdict = {"USE": "git_gcc",
149 "GCC_GITHASH": config.gcc_config.githash,
150 "EMERGE_DEFAULT_OPTS": "--exclude=gcc"}
151 self._SetupBoard(envdict, usepkg_flag=False, clobber_flag=False)
asharif96f59692013-02-16 03:13:36 +0000152
153
154class ToolchainComparator(ChromeOSCheckout):
Han Shen36413122015-08-28 11:05:40 -0700155 def __init__(self, board, remotes, configs, clean,
Han Shen43494292015-09-14 10:26:40 -0700156 public, force_mismatch, noschedv2=False):
asharif96f59692013-02-16 03:13:36 +0000157 self._board = board
158 self._remotes = remotes
159 self._chromeos_root = "chromeos"
160 self._configs = configs
asharif3e38de02013-02-19 19:34:59 +0000161 self._clean = clean
asharife6b72fe2013-02-19 19:58:18 +0000162 self._public = public
asharif58a8c9f2013-02-19 20:42:43 +0000163 self._force_mismatch = force_mismatch
asharif96f59692013-02-16 03:13:36 +0000164 self._ce = command_executer.GetCommandExecuter()
165 self._l = logger.GetLogger()
cmtice7f3190b2015-05-22 14:14:51 -0700166 timestamp = datetime.datetime.strftime(datetime.datetime.now(),
167 "%Y-%m-%d_%H:%M:%S")
Caroline Ticeebbc3da2015-09-03 10:27:20 -0700168 self._reports_dir = os.path.join(NIGHTLY_TESTS_DIR,
cmtice7f3190b2015-05-22 14:14:51 -0700169 "%s.%s" % (timestamp, board),
170 )
Han Shen43494292015-09-14 10:26:40 -0700171 self._noschedv2 = noschedv2
asharif96f59692013-02-16 03:13:36 +0000172 ChromeOSCheckout.__init__(self, board, self._chromeos_root)
173
cmticea6255d02014-01-10 10:27:22 -0800174
175 def _FinishSetup(self):
176 # Get correct .boto file
177 current_dir = os.getcwd()
Caroline Ticeebbc3da2015-09-03 10:27:20 -0700178 src = "/usr/local/google/home/mobiletc-prebuild/.boto"
cmticea6255d02014-01-10 10:27:22 -0800179 dest = os.path.join(current_dir, self._chromeos_root,
180 "src/private-overlays/chromeos-overlay/"
181 "googlestorage_account.boto")
182 # Copy the file to the correct place
183 copy_cmd = "cp %s %s" % (src, dest)
184 retval = self._ce.RunCommand(copy_cmd)
cmtice7f3190b2015-05-22 14:14:51 -0700185 if retval != 0:
186 raise RuntimeError("Couldn't copy .boto file for google storage.")
cmticea6255d02014-01-10 10:27:22 -0800187
188 # Fix protections on ssh key
189 command = ("chmod 600 /var/cache/chromeos-cache/distfiles/target"
190 "/chrome-src-internal/src/third_party/chromite/ssh_keys"
191 "/testing_rsa")
192 retval = self._ce.ChrootRunCommand(self._chromeos_root, command)
cmtice7f3190b2015-05-22 14:14:51 -0700193 if retval != 0:
194 raise RuntimeError("chmod for testing_rsa failed")
cmticea6255d02014-01-10 10:27:22 -0800195
asharif96f59692013-02-16 03:13:36 +0000196 def _TestLabels(self, labels):
197 experiment_file = "toolchain_experiment.txt"
asharif58a8c9f2013-02-19 20:42:43 +0000198 image_args = ""
199 if self._force_mismatch:
asharif0b5d5c82013-02-19 20:42:56 +0000200 image_args = "--force-mismatch"
asharif96f59692013-02-16 03:13:36 +0000201 experiment_header = """
202 board: %s
203 remote: %s
cmticed1f03b82015-06-30 15:19:23 -0700204 retries: 1
asharif96f59692013-02-16 03:13:36 +0000205 """ % (self._board, self._remotes)
206 experiment_tests = """
cmtice0c84ea72015-06-25 14:22:36 -0700207 benchmark: all_toolchain_perf {
cmtice04403882013-11-04 16:38:37 -0500208 suite: telemetry_Crosperf
cmtice6de7f8f2014-03-14 14:08:21 -0700209 iterations: 3
asharif96f59692013-02-16 03:13:36 +0000210 }
211 """
212 with open(experiment_file, "w") as f:
213 print >>f, experiment_header
214 print >>f, experiment_tests
215 for label in labels:
216 # TODO(asharif): Fix crosperf so it accepts labels with symbols
217 crosperf_label = label
Caroline Tice80eab982015-11-04 14:03:14 -0800218 crosperf_label = crosperf_label.replace("-", "_")
219 crosperf_label = crosperf_label.replace("+", "_")
asharife4a5a8f2013-02-19 20:19:33 +0000220 crosperf_label = crosperf_label.replace(".", "")
cmtice56fb7162014-06-18 11:32:15 -0700221
222 # Use the official build instead of building vanilla ourselves.
223 if label == "vanilla":
224 build_name = '%s-release/%s.0.0' % (self._board, self._build_num)
225
226 # Now add 'official build' to test file.
227 official_image = """
228 official_image {
229 chromeos_root: %s
230 build: %s
231 }
232 """ % (self._chromeos_root, build_name)
233 print >>f, official_image
234
cmtice94bc4702014-05-29 16:29:04 -0700235 else:
cmtice56fb7162014-06-18 11:32:15 -0700236 experiment_image = """
237 %s {
238 chromeos_image: %s
239 image_args: %s
240 }
241 """ % (crosperf_label,
242 os.path.join(misc.GetImageDir(self._chromeos_root,
243 self._board),
244 label, "chromiumos_test_image.bin"),
245 image_args)
246 print >>f, experiment_image
247
asharif96f59692013-02-16 03:13:36 +0000248 crosperf = os.path.join(os.path.dirname(__file__),
249 "crosperf",
250 "crosperf")
Han Shen43494292015-09-14 10:26:40 -0700251 noschedv2_opts = '--noschedv2' if self._noschedv2 else ''
Han Shen36413122015-08-28 11:05:40 -0700252 command = ("{crosperf} --no_email=True --results_dir={r_dir} "
Han Shen43494292015-09-14 10:26:40 -0700253 "--json_report=True {noschedv2_opts} {exp_file}").format(
Han Shen36413122015-08-28 11:05:40 -0700254 crosperf=crosperf,
255 r_dir=self._reports_dir,
Han Shen43494292015-09-14 10:26:40 -0700256 noschedv2_opts=noschedv2_opts,
Han Shen36413122015-08-28 11:05:40 -0700257 exp_file=experiment_file)
cmticeaa700b02015-06-12 13:26:47 -0700258
asharif96f59692013-02-16 03:13:36 +0000259 ret = self._ce.RunCommand(command)
cmtice7f3190b2015-05-22 14:14:51 -0700260 if ret != 0:
261 raise RuntimeError("Couldn't run crosperf!")
Caroline Ticeebbc3da2015-09-03 10:27:20 -0700262 else:
263 # Copy json report to pending archives directory.
264 command = "cp %s/*.json %s/." % (self._reports_dir, PENDING_ARCHIVES_DIR)
265 ret = self._ce.RunCommand(command)
cmtice7f3190b2015-05-22 14:14:51 -0700266 return
cmtice56fb7162014-06-18 11:32:15 -0700267
268
269 def _CopyWeeklyReportFiles(self, labels):
270 """Create tar files of the custom and official images and copy them
271 to the weekly reports directory, so they exist when the weekly report
272 gets generated. IMPORTANT NOTE: This function must run *after*
273 crosperf has been run; otherwise the vanilla images will not be there.
274 """
275 images_path = os.path.join(os.path.realpath(self._chromeos_root),
276 "src/build/images", self._board)
277 weekday = time.strftime("%a")
278 data_dir = os.path.join(WEEKLY_REPORTS_ROOT, self._board)
279 dest_dir = os.path.join (data_dir, weekday)
280 if not os.path.exists(dest_dir):
281 os.makedirs(dest_dir)
cmtice4536ef62014-07-08 11:17:21 -0700282 # Make sure dest_dir is empty (clean out last week's data).
283 cmd = "cd %s; rm -Rf %s_*_image*" % (dest_dir, weekday)
284 self._ce.RunCommand(cmd)
285 # Now create new tar files and copy them over.
cmtice56fb7162014-06-18 11:32:15 -0700286 for l in labels:
287 test_path = os.path.join(images_path, l)
288 if os.path.exists(test_path):
289 if l != "vanilla":
290 label_name = "test"
291 else:
292 label_name = "vanilla"
293 tar_file_name = "%s_%s_image.tar" % (weekday, label_name)
Han Shenfe054f12015-02-18 15:00:13 -0800294 cmd = ("cd %s; tar -cvf %s %s/chromiumos_test_image.bin; "
295 "cp %s %s/.") % (images_path,
296 tar_file_name,
297 l, tar_file_name,
298 dest_dir)
cmtice56fb7162014-06-18 11:32:15 -0700299 tar_ret = self._ce.RunCommand(cmd)
cmtice7f3190b2015-05-22 14:14:51 -0700300 if tar_ret != 0:
cmtice56fb7162014-06-18 11:32:15 -0700301 self._l.LogOutput("Error while creating/copying test tar file(%s)."
302 % tar_file_name)
303
cmtice7f3190b2015-05-22 14:14:51 -0700304 def _SendEmail(self):
305 """Find email msesage generated by crosperf and send it."""
306 filename = os.path.join(self._reports_dir, "msg_body.html")
307 if (os.path.exists(filename) and
308 os.path.exists(os.path.expanduser(MAIL_PROGRAM))):
cmtice0495c712015-05-28 15:21:07 -0700309 command = ('cat %s | %s -s "Nightly test results, %s" -team -html'
310 % (filename, MAIL_PROGRAM, self._board))
cmtice7f3190b2015-05-22 14:14:51 -0700311 self._ce.RunCommand(command)
asharif96f59692013-02-16 03:13:36 +0000312
313 def DoAll(self):
314 self._CheckoutChromeOS()
asharif96f59692013-02-16 03:13:36 +0000315 labels = []
cmtice56fb7162014-06-18 11:32:15 -0700316 labels.append("vanilla")
asharif96f59692013-02-16 03:13:36 +0000317 for config in self._configs:
Caroline Tice80eab982015-11-04 14:03:14 -0800318 label = self._BuildLabelName(config.gcc_config.githash, self._board)
asharif96f59692013-02-16 03:13:36 +0000319 if (not misc.DoesLabelExist(self._chromeos_root,
320 self._board,
321 label)):
322 self._BuildToolchain(config)
323 label = self._BuildAndImage(label)
324 labels.append(label)
cmticea6255d02014-01-10 10:27:22 -0800325 self._FinishSetup()
cmticeb4588092015-05-27 08:07:50 -0700326 self._TestLabels(labels)
cmtice7f3190b2015-05-22 14:14:51 -0700327 self._SendEmail()
328 # Only try to copy the image files if the test runs ran successfully.
329 self._CopyWeeklyReportFiles(labels)
asharif3e38de02013-02-19 19:34:59 +0000330 if self._clean:
331 ret = self._DeleteChroot()
cmtice7f3190b2015-05-22 14:14:51 -0700332 if ret != 0:
333 return ret
asharif67973582013-02-19 20:19:40 +0000334 ret = self._DeleteCcahe()
cmtice7f3190b2015-05-22 14:14:51 -0700335 if ret != 0:
336 return ret
asharif96f59692013-02-16 03:13:36 +0000337 return 0
338
339
340def Main(argv):
341 """The main function."""
342 # Common initializations
343### command_executer.InitCommandExecuter(True)
344 command_executer.InitCommandExecuter()
345 parser = optparse.OptionParser()
346 parser.add_option("--remote",
347 dest="remote",
348 help="Remote machines to run tests on.")
349 parser.add_option("--board",
350 dest="board",
351 default="x86-zgb",
352 help="The target board.")
353 parser.add_option("--githashes",
354 dest="githashes",
355 default="master",
356 help="The gcc githashes to test.")
asharif3e38de02013-02-19 19:34:59 +0000357 parser.add_option("--clean",
358 dest="clean",
359 default=False,
360 action="store_true",
361 help="Clean the chroot after testing.")
asharife6b72fe2013-02-19 19:58:18 +0000362 parser.add_option("--public",
363 dest="public",
364 default=False,
365 action="store_true",
366 help="Use the public checkout/build.")
asharif58a8c9f2013-02-19 20:42:43 +0000367 parser.add_option("--force-mismatch",
368 dest="force_mismatch",
369 default="",
370 help="Force the image regardless of board mismatch")
Han Shen43494292015-09-14 10:26:40 -0700371 parser.add_option("--noschedv2",
372 dest="noschedv2",
Han Shen36413122015-08-28 11:05:40 -0700373 action="store_true",
374 default=False,
Han Shen43494292015-09-14 10:26:40 -0700375 help="Pass --noschedv2 to crosperf.")
asharif96f59692013-02-16 03:13:36 +0000376 options, _ = parser.parse_args(argv)
377 if not options.board:
378 print "Please give a board."
379 return 1
380 if not options.remote:
381 print "Please give at least one remote machine."
382 return 1
383 toolchain_configs = []
384 for githash in options.githashes.split(","):
385 gcc_config = GCCConfig(githash=githash)
386 toolchain_config = ToolchainConfig(gcc_config=gcc_config)
387 toolchain_configs.append(toolchain_config)
asharif3e38de02013-02-19 19:34:59 +0000388 fc = ToolchainComparator(options.board, options.remote, toolchain_configs,
asharif58a8c9f2013-02-19 20:42:43 +0000389 options.clean, options.public,
Han Shen36413122015-08-28 11:05:40 -0700390 options.force_mismatch,
Han Shen43494292015-09-14 10:26:40 -0700391 options.noschedv2)
asharif96f59692013-02-16 03:13:36 +0000392 return fc.DoAll()
393
394
395if __name__ == "__main__":
396 retval = Main(sys.argv)
397 sys.exit(retval)