blob: a255c2eb637809876bf500ae453e10407bc2a3c5 [file] [log] [blame]
cmtice46093e52014-12-09 14:59:16 -08001#!/usr/bin/python
2"""
3Script for running nightly compiler tests on ChromeOS.
4
5This script launches a buildbot to build ChromeOS with the latest compiler on
6a particular board; then it finds and downloads the trybot image and the
7corresponding official image, and runs crosperf performance tests comparing
8the two. It then generates a report, emails it to the c-compiler-chrome, as
9well as copying the images into the seven-day reports directory.
10"""
11
12# Script to test different toolchains against ChromeOS benchmarks.
cmticece5ffa42015-02-12 15:18:43 -080013import datetime
cmtice46093e52014-12-09 14:59:16 -080014import optparse
15import os
16import sys
17import time
18import urllib2
19
20from utils import command_executer
21from utils import logger
22
23from utils import buildbot_utils
24
25# CL that updated GCC ebuilds to use 'next_gcc'.
Yunlian Jiang3c6e4672015-08-24 15:58:22 -070026USE_NEXT_GCC_PATCH = "230260"
27
Yunlian Jiang2f563562015-08-28 13:54:04 -070028# CL that uses LLVM to build the peppy image.
29USE_LLVM_PATCH = "295217"
30
Yunlian Jiang3c6e4672015-08-24 15:58:22 -070031# The boards on which we run weekly reports
32WEEKLY_REPORT_BOARDS = ["lumpy"]
cmtice46093e52014-12-09 14:59:16 -080033
Caroline Ticeebbc3da2015-09-03 10:27:20 -070034CROSTC_ROOT = "/usr/local/google/crostc"
cmtice46093e52014-12-09 14:59:16 -080035ROLE_ACCOUNT = "mobiletc-prebuild"
36TOOLCHAIN_DIR = os.path.dirname(os.path.realpath(__file__))
cmtice7f3190b2015-05-22 14:14:51 -070037MAIL_PROGRAM = "~/var/bin/mail-sheriff"
Caroline Ticeebbc3da2015-09-03 10:27:20 -070038WEEKLY_REPORTS_ROOT = os.path.join(CROSTC_ROOT, "weekly_test_data")
39PENDING_ARCHIVES_DIR = os.path.join(CROSTC_ROOT, "pending_archives")
40NIGHTLY_TESTS_DIR = os.path.join(CROSTC_ROOT, "nightly_test_reports")
cmtice46093e52014-12-09 14:59:16 -080041
42class ToolchainComparator():
43 """
44 Class for doing the nightly tests work.
45 """
46
Han Shen43494292015-09-14 10:26:40 -070047 def __init__(self, board, remotes, chromeos_root, weekday, patches, noschedv2=False):
cmtice46093e52014-12-09 14:59:16 -080048 self._board = board
49 self._remotes = remotes
50 self._chromeos_root = chromeos_root
51 self._base_dir = os.getcwd()
52 self._ce = command_executer.GetCommandExecuter()
53 self._l = logger.GetLogger()
54 self._build = "%s-release" % board
Yunlian Jiang3c6e4672015-08-24 15:58:22 -070055 self._patches = patches.split(',')
56 self._patches_string = '_'.join(str(p) for p in self._patches)
Han Shen43494292015-09-14 10:26:40 -070057 self._noschedv2 = noschedv2
Yunlian Jiang3c6e4672015-08-24 15:58:22 -070058
cmtice46093e52014-12-09 14:59:16 -080059 if not weekday:
60 self._weekday = time.strftime("%a")
61 else:
62 self._weekday = weekday
cmtice7f3190b2015-05-22 14:14:51 -070063 timestamp = datetime.datetime.strftime(datetime.datetime.now(),
64 "%Y-%m-%d_%H:%M:%S")
Caroline Ticeebbc3da2015-09-03 10:27:20 -070065 self._reports_dir = os.path.join(NIGHTLY_TESTS_DIR,
cmtice7f3190b2015-05-22 14:14:51 -070066 "%s.%s" % (timestamp, board),
67 )
cmtice46093e52014-12-09 14:59:16 -080068
69 def _ParseVanillaImage(self, trybot_image):
70 """
71 Parse a trybot artifact name to get corresponding vanilla image.
72
73 This function takes an artifact name, such as
74 'trybot-daisy-release/R40-6394.0.0-b1389', and returns the
75 corresponding official build name, e.g. 'daisy-release/R40-6394.0.0'.
76 """
77 start_pos = trybot_image.find(self._build)
78 end_pos = trybot_image.rfind("-b")
79 vanilla_image = trybot_image[start_pos:end_pos]
80 return vanilla_image
81
cmtice46093e52014-12-09 14:59:16 -080082 def _FinishSetup(self):
83 """
84 Make sure testing_rsa file is properly set up.
85 """
86 # Fix protections on ssh key
87 command = ("chmod 600 /var/cache/chromeos-cache/distfiles/target"
88 "/chrome-src-internal/src/third_party/chromite/ssh_keys"
89 "/testing_rsa")
90 ret_val = self._ce.ChrootRunCommand(self._chromeos_root, command)
cmtice7f3190b2015-05-22 14:14:51 -070091 if ret_val != 0:
92 raise RuntimeError("chmod for testing_rsa failed")
cmtice46093e52014-12-09 14:59:16 -080093
94 def _TestImages(self, trybot_image, vanilla_image):
95 """
96 Create crosperf experiment file.
97
98 Given the names of the trybot and vanilla images, create the
99 appropriate crosperf experiment file and launch crosperf on it.
100 """
101 experiment_file_dir = os.path.join (self._chromeos_root, "..",
102 self._weekday)
103 experiment_file_name = "%s_toolchain_experiment.txt" % self._board
Yunlian Jiang2f563562015-08-28 13:54:04 -0700104
Caroline Ticeddde5052015-09-23 09:43:35 -0700105 compiler_string = "gcc"
Yunlian Jiang2f563562015-08-28 13:54:04 -0700106 if self._patches_string == USE_LLVM_PATCH:
107 experiment_file_name = "%s_llvm_experiment.txt" % self._board
Caroline Ticeddde5052015-09-23 09:43:35 -0700108 compiler_string = "llvm"
Yunlian Jiang2f563562015-08-28 13:54:04 -0700109
cmtice46093e52014-12-09 14:59:16 -0800110 experiment_file = os.path.join (experiment_file_dir,
111 experiment_file_name)
112 experiment_header = """
113 board: %s
114 remote: %s
Luis Lozanoe1efeb82015-06-16 16:35:44 -0700115 retries: 1
cmtice46093e52014-12-09 14:59:16 -0800116 """ % (self._board, self._remotes)
117 experiment_tests = """
cmtice0c84ea72015-06-25 14:22:36 -0700118 benchmark: all_toolchain_perf {
cmtice46093e52014-12-09 14:59:16 -0800119 suite: telemetry_Crosperf
120 iterations: 3
121 }
122 """
123 with open(experiment_file, "w") as f:
124 print >> f, experiment_header
125 print >> f, experiment_tests
126
127 # Now add vanilla to test file.
128 official_image = """
129 vanilla_image {
130 chromeos_root: %s
131 build: %s
Caroline Ticeddde5052015-09-23 09:43:35 -0700132 compiler: gcc
cmtice46093e52014-12-09 14:59:16 -0800133 }
134 """ % (self._chromeos_root, vanilla_image)
135 print >> f, official_image
136
Caroline Tice80eab982015-11-04 14:03:14 -0800137 label_string = "%s_trybot_image" % compiler_string
138 if USE_NEXT_GCC_PATCH in self._patches:
139 label_string = "gcc_next_trybot_image"
140
cmtice46093e52014-12-09 14:59:16 -0800141 experiment_image = """
Caroline Tice80eab982015-11-04 14:03:14 -0800142 %s {
cmtice46093e52014-12-09 14:59:16 -0800143 chromeos_root: %s
144 build: %s
Caroline Ticeddde5052015-09-23 09:43:35 -0700145 compiler: %s
cmtice46093e52014-12-09 14:59:16 -0800146 }
Caroline Tice80eab982015-11-04 14:03:14 -0800147 """ % (label_string, self._chromeos_root, trybot_image,
148 compiler_string)
cmtice46093e52014-12-09 14:59:16 -0800149 print >> f, experiment_image
150
151 crosperf = os.path.join(TOOLCHAIN_DIR,
152 "crosperf",
153 "crosperf")
Han Shen43494292015-09-14 10:26:40 -0700154 noschedv2_opts = '--noschedv2' if self._noschedv2 else ''
Han Shen36413122015-08-28 11:05:40 -0700155 command = ("{crosperf} --no_email=True --results_dir={r_dir} "
Han Shen43494292015-09-14 10:26:40 -0700156 "--json_report=True {noschedv2_opts} {exp_file}").format(
Han Shen36413122015-08-28 11:05:40 -0700157 crosperf=crosperf,
158 r_dir=self._reports_dir,
Han Shen43494292015-09-14 10:26:40 -0700159 noschedv2_opts=noschedv2_opts,
Han Shen36413122015-08-28 11:05:40 -0700160 exp_file=experiment_file)
cmticeaa700b02015-06-12 13:26:47 -0700161
cmtice46093e52014-12-09 14:59:16 -0800162 ret = self._ce.RunCommand(command)
cmtice7f3190b2015-05-22 14:14:51 -0700163 if ret != 0:
164 raise RuntimeError("Couldn't run crosperf!")
Caroline Ticeebbc3da2015-09-03 10:27:20 -0700165 else:
166 # Copy json report to pending archives directory.
167 command = "cp %s/*.json %s/." % (self._reports_dir, PENDING_ARCHIVES_DIR)
168 ret = self._ce.RunCommand(command)
cmtice7f3190b2015-05-22 14:14:51 -0700169 return
cmtice46093e52014-12-09 14:59:16 -0800170
171 def _CopyWeeklyReportFiles(self, trybot_image, vanilla_image):
172 """
173 Put files in place for running seven-day reports.
174
175 Create tar files of the custom and official images and copy them
176 to the weekly reports directory, so they exist when the weekly report
177 gets generated. IMPORTANT NOTE: This function must run *after*
178 crosperf has been run; otherwise the vanilla images will not be there.
179 """
180
181 dry_run = False
182 if (os.getlogin() != ROLE_ACCOUNT):
183 self._l.LogOutput("Running this from non-role account; not copying "
184 "tar files for weekly reports.")
185 dry_run = True
186
187 images_path = os.path.join(os.path.realpath(self._chromeos_root),
188 "chroot/tmp")
189
190 data_dir = os.path.join(WEEKLY_REPORTS_ROOT, self._board)
191 dest_dir = os.path.join (data_dir, self._weekday)
192 if not os.path.exists(dest_dir):
193 os.makedirs(dest_dir)
194
195 # Make sure dest_dir is empty (clean out last week's data).
196 cmd = "cd %s; rm -Rf %s_*_image*" % (dest_dir, self._weekday)
197 if dry_run:
198 print "CMD: %s" % cmd
199 else:
200 self._ce.RunCommand(cmd)
201
202 # Now create new tar files and copy them over.
203 labels = [ "test", "vanilla" ]
204 for label_name in labels:
205 if label_name == "test":
206 test_path = trybot_image
207 else:
208 test_path = vanilla_image
209 tar_file_name = "%s_%s_image.tar" % (self._weekday, label_name)
Han Shenfe054f12015-02-18 15:00:13 -0800210 cmd = ("cd %s; tar -cvf %s %s/chromiumos_test_image.bin; "
211 "cp %s %s/.") % (images_path,
212 tar_file_name,
213 test_path,
214 tar_file_name,
215 dest_dir)
cmtice46093e52014-12-09 14:59:16 -0800216 if dry_run:
217 print "CMD: %s" % cmd
218 tar_ret = 0
219 else:
220 tar_ret = self._ce.RunCommand(cmd)
221 if tar_ret:
222 self._l.LogOutput("Error while creating/copying test tar file(%s)."
223 % tar_file_name)
224
cmtice7f3190b2015-05-22 14:14:51 -0700225 def _SendEmail(self):
226 """Find email message generated by crosperf and send it."""
227 filename = os.path.join(self._reports_dir,
228 "msg_body.html")
229 if (os.path.exists(filename) and
230 os.path.exists(os.path.expanduser(MAIL_PROGRAM))):
Yunlian Jiang2f563562015-08-28 13:54:04 -0700231 email_title = "buildbot test results"
232 if self._patches_string == USE_LLVM_PATCH:
233 email_title = "buildbot llvm test results"
234 command = ('cat %s | %s -s "%s, %s" -team -html'
235 % (filename, MAIL_PROGRAM, email_title, self._board))
cmtice7f3190b2015-05-22 14:14:51 -0700236 self._ce.RunCommand(command)
cmtice46093e52014-12-09 14:59:16 -0800237
238 def DoAll(self):
239 """
240 Main function inside ToolchainComparator class.
241
242 Launch trybot, get image names, create crosperf experiment file, run
243 crosperf, and copy images into seven-day report directories.
244 """
cmticece5ffa42015-02-12 15:18:43 -0800245 date_str = datetime.date.today()
Yunlian Jiang3c6e4672015-08-24 15:58:22 -0700246 description = "master_%s_%s_%s" % (self._patches_string,
Han Shenfe054f12015-02-18 15:00:13 -0800247 self._build,
248 date_str)
cmtice46093e52014-12-09 14:59:16 -0800249 trybot_image = buildbot_utils.GetTrybotImage(self._chromeos_root,
250 self._build,
Yunlian Jiang3c6e4672015-08-24 15:58:22 -0700251 self._patches,
Luis Lozano8a68b2d2015-04-23 14:37:09 -0700252 description,
253 build_toolchain=True)
cmtice46093e52014-12-09 14:59:16 -0800254
255 vanilla_image = self._ParseVanillaImage(trybot_image)
256
257 print ("trybot_image: %s" % trybot_image)
258 print ("vanilla_image: %s" % vanilla_image)
cmticed54f9802015-02-05 11:04:11 -0800259 if len(trybot_image) == 0:
260 self._l.LogError("Unable to find trybot_image for %s!" % description)
261 return 1
262 if len(vanilla_image) == 0:
263 self._l.LogError("Unable to find vanilla image for %s!" % description)
264 return 1
cmtice46093e52014-12-09 14:59:16 -0800265 if os.getlogin() == ROLE_ACCOUNT:
266 self._FinishSetup()
267
cmtice7f3190b2015-05-22 14:14:51 -0700268 self._TestImages(trybot_image, vanilla_image)
269 self._SendEmail()
Yunlian Jiang3c6e4672015-08-24 15:58:22 -0700270 if (self._patches_string == USE_NEXT_GCC_PATCH and
271 self._board in WEEKLY_REPORT_BOARDS):
272 # Only try to copy the image files if the test runs ran successfully.
273 self._CopyWeeklyReportFiles(trybot_image, vanilla_image)
cmtice46093e52014-12-09 14:59:16 -0800274 return 0
275
276
277def Main(argv):
278 """The main function."""
279
280 # Common initializations
281 command_executer.InitCommandExecuter()
282 parser = optparse.OptionParser()
283 parser.add_option("--remote",
284 dest="remote",
285 help="Remote machines to run tests on.")
286 parser.add_option("--board",
287 dest="board",
288 default="x86-zgb",
289 help="The target board.")
290 parser.add_option("--chromeos_root",
291 dest="chromeos_root",
292 help="The chromeos root from which to run tests.")
293 parser.add_option("--weekday", default="",
294 dest="weekday",
295 help="The day of the week for which to run tests.")
Yunlian Jiange52838c2015-08-20 14:32:37 -0700296 parser.add_option("--patch",
297 dest="patches",
298 help="The patches to use for the testing, "
299 "seprate the patch numbers with ',' "
300 "for more than one patches.")
Han Shen43494292015-09-14 10:26:40 -0700301 parser.add_option("--noschedv2",
302 dest="noschedv2",
Han Shen36413122015-08-28 11:05:40 -0700303 action="store_true",
304 default=False,
Han Shen43494292015-09-14 10:26:40 -0700305 help="Pass --noschedv2 to crosperf.")
Han Shen36413122015-08-28 11:05:40 -0700306
cmtice46093e52014-12-09 14:59:16 -0800307 options, _ = parser.parse_args(argv)
308 if not options.board:
309 print "Please give a board."
310 return 1
311 if not options.remote:
312 print "Please give at least one remote machine."
313 return 1
314 if not options.chromeos_root:
315 print "Please specify the ChromeOS root directory."
316 return 1
Yunlian Jiang76259e62015-08-21 08:44:31 -0700317 if options.patches:
Yunlian Jiang3c6e4672015-08-24 15:58:22 -0700318 patches = options.patches
319 else:
320 patches = USE_NEXT_GCC_PATCH
Yunlian Jiange52838c2015-08-20 14:32:37 -0700321
cmtice46093e52014-12-09 14:59:16 -0800322 fc = ToolchainComparator(options.board, options.remote,
Han Shen36413122015-08-28 11:05:40 -0700323 options.chromeos_root, options.weekday, patches,
Han Shen43494292015-09-14 10:26:40 -0700324 options.noschedv2)
cmtice46093e52014-12-09 14:59:16 -0800325 return fc.DoAll()
326
327
328if __name__ == "__main__":
329 retval = Main(sys.argv)
330 sys.exit(retval)