blob: 4717089987611e3621b95e4f6e221e6624bfd16e [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):
asharif58a8c9f2013-02-19 20:42:43 +0000149 def __init__(self, board, remotes, configs, clean, public, force_mismatch):
asharif96f59692013-02-16 03:13:36 +0000150 self._board = board
151 self._remotes = remotes
152 self._chromeos_root = "chromeos"
153 self._configs = configs
asharif3e38de02013-02-19 19:34:59 +0000154 self._clean = clean
asharife6b72fe2013-02-19 19:58:18 +0000155 self._public = public
asharif58a8c9f2013-02-19 20:42:43 +0000156 self._force_mismatch = force_mismatch
asharif96f59692013-02-16 03:13:36 +0000157 self._ce = command_executer.GetCommandExecuter()
158 self._l = logger.GetLogger()
cmtice7f3190b2015-05-22 14:14:51 -0700159 timestamp = datetime.datetime.strftime(datetime.datetime.now(),
160 "%Y-%m-%d_%H:%M:%S")
161 self._reports_dir = os.path.join(
162 os.path.expanduser("~/nightly_test_reports"),
163 "%s.%s" % (timestamp, board),
164 )
asharif96f59692013-02-16 03:13:36 +0000165 ChromeOSCheckout.__init__(self, board, self._chromeos_root)
166
cmticea6255d02014-01-10 10:27:22 -0800167
168 def _FinishSetup(self):
169 # Get correct .boto file
170 current_dir = os.getcwd()
171 src = "/home/mobiletc-prebuild/.boto"
172 dest = os.path.join(current_dir, self._chromeos_root,
173 "src/private-overlays/chromeos-overlay/"
174 "googlestorage_account.boto")
175 # Copy the file to the correct place
176 copy_cmd = "cp %s %s" % (src, dest)
177 retval = self._ce.RunCommand(copy_cmd)
cmtice7f3190b2015-05-22 14:14:51 -0700178 if retval != 0:
179 raise RuntimeError("Couldn't copy .boto file for google storage.")
cmticea6255d02014-01-10 10:27:22 -0800180
181 # Fix protections on ssh key
182 command = ("chmod 600 /var/cache/chromeos-cache/distfiles/target"
183 "/chrome-src-internal/src/third_party/chromite/ssh_keys"
184 "/testing_rsa")
185 retval = self._ce.ChrootRunCommand(self._chromeos_root, command)
cmtice7f3190b2015-05-22 14:14:51 -0700186 if retval != 0:
187 raise RuntimeError("chmod for testing_rsa failed")
cmticea6255d02014-01-10 10:27:22 -0800188
asharif96f59692013-02-16 03:13:36 +0000189 def _TestLabels(self, labels):
190 experiment_file = "toolchain_experiment.txt"
asharif58a8c9f2013-02-19 20:42:43 +0000191 image_args = ""
192 if self._force_mismatch:
asharif0b5d5c82013-02-19 20:42:56 +0000193 image_args = "--force-mismatch"
asharif96f59692013-02-16 03:13:36 +0000194 experiment_header = """
195 board: %s
196 remote: %s
cmticed1f03b82015-06-30 15:19:23 -0700197 retries: 1
asharif96f59692013-02-16 03:13:36 +0000198 """ % (self._board, self._remotes)
199 experiment_tests = """
cmtice0c84ea72015-06-25 14:22:36 -0700200 benchmark: all_toolchain_perf {
cmtice04403882013-11-04 16:38:37 -0500201 suite: telemetry_Crosperf
cmtice6de7f8f2014-03-14 14:08:21 -0700202 iterations: 3
asharif96f59692013-02-16 03:13:36 +0000203 }
204 """
205 with open(experiment_file, "w") as f:
206 print >>f, experiment_header
207 print >>f, experiment_tests
208 for label in labels:
209 # TODO(asharif): Fix crosperf so it accepts labels with symbols
210 crosperf_label = label
211 crosperf_label = crosperf_label.replace("-", "minus")
212 crosperf_label = crosperf_label.replace("+", "plus")
asharife4a5a8f2013-02-19 20:19:33 +0000213 crosperf_label = crosperf_label.replace(".", "")
cmtice56fb7162014-06-18 11:32:15 -0700214
215 # Use the official build instead of building vanilla ourselves.
216 if label == "vanilla":
217 build_name = '%s-release/%s.0.0' % (self._board, self._build_num)
218
219 # Now add 'official build' to test file.
220 official_image = """
221 official_image {
222 chromeos_root: %s
223 build: %s
224 }
225 """ % (self._chromeos_root, build_name)
226 print >>f, official_image
227
cmtice94bc4702014-05-29 16:29:04 -0700228 else:
cmtice56fb7162014-06-18 11:32:15 -0700229 experiment_image = """
230 %s {
231 chromeos_image: %s
232 image_args: %s
233 }
234 """ % (crosperf_label,
235 os.path.join(misc.GetImageDir(self._chromeos_root,
236 self._board),
237 label, "chromiumos_test_image.bin"),
238 image_args)
239 print >>f, experiment_image
240
asharif96f59692013-02-16 03:13:36 +0000241 crosperf = os.path.join(os.path.dirname(__file__),
242 "crosperf",
243 "crosperf")
cmtice9db7ae52015-06-23 10:34:39 -0700244 command = ("%s --no_email=True --results_dir=%s %s" %
cmtice78f25952015-06-19 09:16:12 -0700245 (crosperf, self._reports_dir, experiment_file))
cmticeaa700b02015-06-12 13:26:47 -0700246
asharif96f59692013-02-16 03:13:36 +0000247 ret = self._ce.RunCommand(command)
cmtice7f3190b2015-05-22 14:14:51 -0700248 if ret != 0:
249 raise RuntimeError("Couldn't run crosperf!")
250 return
cmtice56fb7162014-06-18 11:32:15 -0700251
252
253 def _CopyWeeklyReportFiles(self, labels):
254 """Create tar files of the custom and official images and copy them
255 to the weekly reports directory, so they exist when the weekly report
256 gets generated. IMPORTANT NOTE: This function must run *after*
257 crosperf has been run; otherwise the vanilla images will not be there.
258 """
259 images_path = os.path.join(os.path.realpath(self._chromeos_root),
260 "src/build/images", self._board)
261 weekday = time.strftime("%a")
262 data_dir = os.path.join(WEEKLY_REPORTS_ROOT, self._board)
263 dest_dir = os.path.join (data_dir, weekday)
264 if not os.path.exists(dest_dir):
265 os.makedirs(dest_dir)
cmtice4536ef62014-07-08 11:17:21 -0700266 # Make sure dest_dir is empty (clean out last week's data).
267 cmd = "cd %s; rm -Rf %s_*_image*" % (dest_dir, weekday)
268 self._ce.RunCommand(cmd)
269 # Now create new tar files and copy them over.
cmtice56fb7162014-06-18 11:32:15 -0700270 for l in labels:
271 test_path = os.path.join(images_path, l)
272 if os.path.exists(test_path):
273 if l != "vanilla":
274 label_name = "test"
275 else:
276 label_name = "vanilla"
277 tar_file_name = "%s_%s_image.tar" % (weekday, label_name)
Han Shenfe054f12015-02-18 15:00:13 -0800278 cmd = ("cd %s; tar -cvf %s %s/chromiumos_test_image.bin; "
279 "cp %s %s/.") % (images_path,
280 tar_file_name,
281 l, tar_file_name,
282 dest_dir)
cmtice56fb7162014-06-18 11:32:15 -0700283 tar_ret = self._ce.RunCommand(cmd)
cmtice7f3190b2015-05-22 14:14:51 -0700284 if tar_ret != 0:
cmtice56fb7162014-06-18 11:32:15 -0700285 self._l.LogOutput("Error while creating/copying test tar file(%s)."
286 % tar_file_name)
287
cmtice7f3190b2015-05-22 14:14:51 -0700288 def _SendEmail(self):
289 """Find email msesage generated by crosperf and send it."""
290 filename = os.path.join(self._reports_dir, "msg_body.html")
291 if (os.path.exists(filename) and
292 os.path.exists(os.path.expanduser(MAIL_PROGRAM))):
cmtice0495c712015-05-28 15:21:07 -0700293 command = ('cat %s | %s -s "Nightly test results, %s" -team -html'
294 % (filename, MAIL_PROGRAM, self._board))
cmtice7f3190b2015-05-22 14:14:51 -0700295 self._ce.RunCommand(command)
asharif96f59692013-02-16 03:13:36 +0000296
297 def DoAll(self):
298 self._CheckoutChromeOS()
asharif96f59692013-02-16 03:13:36 +0000299 labels = []
cmtice56fb7162014-06-18 11:32:15 -0700300 labels.append("vanilla")
asharif96f59692013-02-16 03:13:36 +0000301 for config in self._configs:
302 label = misc.GetFilenameFromString(config.gcc_config.githash)
303 if (not misc.DoesLabelExist(self._chromeos_root,
304 self._board,
305 label)):
306 self._BuildToolchain(config)
307 label = self._BuildAndImage(label)
308 labels.append(label)
cmticea6255d02014-01-10 10:27:22 -0800309 self._FinishSetup()
cmticeb4588092015-05-27 08:07:50 -0700310 self._TestLabels(labels)
cmtice7f3190b2015-05-22 14:14:51 -0700311 self._SendEmail()
312 # Only try to copy the image files if the test runs ran successfully.
313 self._CopyWeeklyReportFiles(labels)
asharif3e38de02013-02-19 19:34:59 +0000314 if self._clean:
315 ret = self._DeleteChroot()
cmtice7f3190b2015-05-22 14:14:51 -0700316 if ret != 0:
317 return ret
asharif67973582013-02-19 20:19:40 +0000318 ret = self._DeleteCcahe()
cmtice7f3190b2015-05-22 14:14:51 -0700319 if ret != 0:
320 return ret
asharif96f59692013-02-16 03:13:36 +0000321 return 0
322
323
324def Main(argv):
325 """The main function."""
326 # Common initializations
327### command_executer.InitCommandExecuter(True)
328 command_executer.InitCommandExecuter()
329 parser = optparse.OptionParser()
330 parser.add_option("--remote",
331 dest="remote",
332 help="Remote machines to run tests on.")
333 parser.add_option("--board",
334 dest="board",
335 default="x86-zgb",
336 help="The target board.")
337 parser.add_option("--githashes",
338 dest="githashes",
339 default="master",
340 help="The gcc githashes to test.")
asharif3e38de02013-02-19 19:34:59 +0000341 parser.add_option("--clean",
342 dest="clean",
343 default=False,
344 action="store_true",
345 help="Clean the chroot after testing.")
asharife6b72fe2013-02-19 19:58:18 +0000346 parser.add_option("--public",
347 dest="public",
348 default=False,
349 action="store_true",
350 help="Use the public checkout/build.")
asharif58a8c9f2013-02-19 20:42:43 +0000351 parser.add_option("--force-mismatch",
352 dest="force_mismatch",
353 default="",
354 help="Force the image regardless of board mismatch")
asharif96f59692013-02-16 03:13:36 +0000355 options, _ = parser.parse_args(argv)
356 if not options.board:
357 print "Please give a board."
358 return 1
359 if not options.remote:
360 print "Please give at least one remote machine."
361 return 1
362 toolchain_configs = []
363 for githash in options.githashes.split(","):
364 gcc_config = GCCConfig(githash=githash)
365 toolchain_config = ToolchainConfig(gcc_config=gcc_config)
366 toolchain_configs.append(toolchain_config)
asharif3e38de02013-02-19 19:34:59 +0000367 fc = ToolchainComparator(options.board, options.remote, toolchain_configs,
asharif58a8c9f2013-02-19 20:42:43 +0000368 options.clean, options.public,
369 options.force_mismatch)
asharif96f59692013-02-16 03:13:36 +0000370 return fc.DoAll()
371
372
373if __name__ == "__main__":
374 retval = Main(sys.argv)
375 sys.exit(retval)