blob: d4a99814ace706ca89490305ec5ee62f0a440f48 [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
cmtice46093e52014-12-09 14:59:16 -080018
19from utils import command_executer
20from utils import logger
21
22from utils import buildbot_utils
23
24# CL that updated GCC ebuilds to use 'next_gcc'.
Yunlian Jiang3c6e4672015-08-24 15:58:22 -070025USE_NEXT_GCC_PATCH = "230260"
26
Yunlian Jiang2f563562015-08-28 13:54:04 -070027# CL that uses LLVM to build the peppy image.
28USE_LLVM_PATCH = "295217"
29
Yunlian Jiang3c6e4672015-08-24 15:58:22 -070030# The boards on which we run weekly reports
31WEEKLY_REPORT_BOARDS = ["lumpy"]
cmtice46093e52014-12-09 14:59:16 -080032
Caroline Ticeebbc3da2015-09-03 10:27:20 -070033CROSTC_ROOT = "/usr/local/google/crostc"
cmtice46093e52014-12-09 14:59:16 -080034ROLE_ACCOUNT = "mobiletc-prebuild"
35TOOLCHAIN_DIR = os.path.dirname(os.path.realpath(__file__))
cmtice7f3190b2015-05-22 14:14:51 -070036MAIL_PROGRAM = "~/var/bin/mail-sheriff"
Caroline Ticeebbc3da2015-09-03 10:27:20 -070037WEEKLY_REPORTS_ROOT = os.path.join(CROSTC_ROOT, "weekly_test_data")
38PENDING_ARCHIVES_DIR = os.path.join(CROSTC_ROOT, "pending_archives")
39NIGHTLY_TESTS_DIR = os.path.join(CROSTC_ROOT, "nightly_test_reports")
cmtice46093e52014-12-09 14:59:16 -080040
41class ToolchainComparator():
42 """
43 Class for doing the nightly tests work.
44 """
45
Han Shen43494292015-09-14 10:26:40 -070046 def __init__(self, board, remotes, chromeos_root, weekday, patches, noschedv2=False):
cmtice46093e52014-12-09 14:59:16 -080047 self._board = board
48 self._remotes = remotes
49 self._chromeos_root = chromeos_root
50 self._base_dir = os.getcwd()
51 self._ce = command_executer.GetCommandExecuter()
52 self._l = logger.GetLogger()
53 self._build = "%s-release" % board
Yunlian Jiang3c6e4672015-08-24 15:58:22 -070054 self._patches = patches.split(',')
55 self._patches_string = '_'.join(str(p) for p in self._patches)
Han Shen43494292015-09-14 10:26:40 -070056 self._noschedv2 = noschedv2
Yunlian Jiang3c6e4672015-08-24 15:58:22 -070057
cmtice46093e52014-12-09 14:59:16 -080058 if not weekday:
59 self._weekday = time.strftime("%a")
60 else:
61 self._weekday = weekday
cmtice7f3190b2015-05-22 14:14:51 -070062 timestamp = datetime.datetime.strftime(datetime.datetime.now(),
63 "%Y-%m-%d_%H:%M:%S")
Caroline Ticeebbc3da2015-09-03 10:27:20 -070064 self._reports_dir = os.path.join(NIGHTLY_TESTS_DIR,
cmtice7f3190b2015-05-22 14:14:51 -070065 "%s.%s" % (timestamp, board),
66 )
cmtice46093e52014-12-09 14:59:16 -080067
68 def _ParseVanillaImage(self, trybot_image):
69 """
70 Parse a trybot artifact name to get corresponding vanilla image.
71
72 This function takes an artifact name, such as
73 'trybot-daisy-release/R40-6394.0.0-b1389', and returns the
74 corresponding official build name, e.g. 'daisy-release/R40-6394.0.0'.
75 """
76 start_pos = trybot_image.find(self._build)
77 end_pos = trybot_image.rfind("-b")
78 vanilla_image = trybot_image[start_pos:end_pos]
79 return vanilla_image
80
cmtice46093e52014-12-09 14:59:16 -080081 def _FinishSetup(self):
82 """
83 Make sure testing_rsa file is properly set up.
84 """
85 # Fix protections on ssh key
86 command = ("chmod 600 /var/cache/chromeos-cache/distfiles/target"
87 "/chrome-src-internal/src/third_party/chromite/ssh_keys"
88 "/testing_rsa")
89 ret_val = self._ce.ChrootRunCommand(self._chromeos_root, command)
cmtice7f3190b2015-05-22 14:14:51 -070090 if ret_val != 0:
91 raise RuntimeError("chmod for testing_rsa failed")
cmtice46093e52014-12-09 14:59:16 -080092
93 def _TestImages(self, trybot_image, vanilla_image):
94 """
95 Create crosperf experiment file.
96
97 Given the names of the trybot and vanilla images, create the
98 appropriate crosperf experiment file and launch crosperf on it.
99 """
100 experiment_file_dir = os.path.join (self._chromeos_root, "..",
101 self._weekday)
102 experiment_file_name = "%s_toolchain_experiment.txt" % self._board
Yunlian Jiang2f563562015-08-28 13:54:04 -0700103
Caroline Ticeddde5052015-09-23 09:43:35 -0700104 compiler_string = "gcc"
Yunlian Jiang2f563562015-08-28 13:54:04 -0700105 if self._patches_string == USE_LLVM_PATCH:
106 experiment_file_name = "%s_llvm_experiment.txt" % self._board
Caroline Ticeddde5052015-09-23 09:43:35 -0700107 compiler_string = "llvm"
Yunlian Jiang2f563562015-08-28 13:54:04 -0700108
cmtice46093e52014-12-09 14:59:16 -0800109 experiment_file = os.path.join (experiment_file_dir,
110 experiment_file_name)
111 experiment_header = """
112 board: %s
113 remote: %s
Luis Lozanoe1efeb82015-06-16 16:35:44 -0700114 retries: 1
cmtice46093e52014-12-09 14:59:16 -0800115 """ % (self._board, self._remotes)
116 experiment_tests = """
Luis Lozano1489d642015-12-08 10:08:19 -0800117 benchmark: all_toolchain_perf {
cmtice46093e52014-12-09 14:59:16 -0800118 suite: telemetry_Crosperf
119 iterations: 3
120 }
121 """
122 with open(experiment_file, "w") as f:
123 print >> f, experiment_header
124 print >> f, experiment_tests
125
126 # Now add vanilla to test file.
127 official_image = """
128 vanilla_image {
129 chromeos_root: %s
130 build: %s
Caroline Ticeddde5052015-09-23 09:43:35 -0700131 compiler: gcc
cmtice46093e52014-12-09 14:59:16 -0800132 }
133 """ % (self._chromeos_root, vanilla_image)
134 print >> f, official_image
135
Caroline Tice80eab982015-11-04 14:03:14 -0800136 label_string = "%s_trybot_image" % compiler_string
137 if USE_NEXT_GCC_PATCH in self._patches:
138 label_string = "gcc_next_trybot_image"
139
cmtice46093e52014-12-09 14:59:16 -0800140 experiment_image = """
Caroline Tice80eab982015-11-04 14:03:14 -0800141 %s {
cmtice46093e52014-12-09 14:59:16 -0800142 chromeos_root: %s
143 build: %s
Caroline Ticeddde5052015-09-23 09:43:35 -0700144 compiler: %s
cmtice46093e52014-12-09 14:59:16 -0800145 }
Caroline Tice80eab982015-11-04 14:03:14 -0800146 """ % (label_string, self._chromeos_root, trybot_image,
147 compiler_string)
cmtice46093e52014-12-09 14:59:16 -0800148 print >> f, experiment_image
149
150 crosperf = os.path.join(TOOLCHAIN_DIR,
151 "crosperf",
152 "crosperf")
Han Shen43494292015-09-14 10:26:40 -0700153 noschedv2_opts = '--noschedv2' if self._noschedv2 else ''
Han Shen36413122015-08-28 11:05:40 -0700154 command = ("{crosperf} --no_email=True --results_dir={r_dir} "
Han Shen43494292015-09-14 10:26:40 -0700155 "--json_report=True {noschedv2_opts} {exp_file}").format(
Han Shen36413122015-08-28 11:05:40 -0700156 crosperf=crosperf,
157 r_dir=self._reports_dir,
Han Shen43494292015-09-14 10:26:40 -0700158 noschedv2_opts=noschedv2_opts,
Han Shen36413122015-08-28 11:05:40 -0700159 exp_file=experiment_file)
cmticeaa700b02015-06-12 13:26:47 -0700160
cmtice46093e52014-12-09 14:59:16 -0800161 ret = self._ce.RunCommand(command)
cmtice7f3190b2015-05-22 14:14:51 -0700162 if ret != 0:
163 raise RuntimeError("Couldn't run crosperf!")
Caroline Ticeebbc3da2015-09-03 10:27:20 -0700164 else:
165 # Copy json report to pending archives directory.
166 command = "cp %s/*.json %s/." % (self._reports_dir, PENDING_ARCHIVES_DIR)
167 ret = self._ce.RunCommand(command)
cmtice7f3190b2015-05-22 14:14:51 -0700168 return
cmtice46093e52014-12-09 14:59:16 -0800169
170 def _CopyWeeklyReportFiles(self, trybot_image, vanilla_image):
171 """
172 Put files in place for running seven-day reports.
173
174 Create tar files of the custom and official images and copy them
175 to the weekly reports directory, so they exist when the weekly report
176 gets generated. IMPORTANT NOTE: This function must run *after*
177 crosperf has been run; otherwise the vanilla images will not be there.
178 """
179
180 dry_run = False
181 if (os.getlogin() != ROLE_ACCOUNT):
182 self._l.LogOutput("Running this from non-role account; not copying "
183 "tar files for weekly reports.")
184 dry_run = True
185
186 images_path = os.path.join(os.path.realpath(self._chromeos_root),
187 "chroot/tmp")
188
189 data_dir = os.path.join(WEEKLY_REPORTS_ROOT, self._board)
190 dest_dir = os.path.join (data_dir, self._weekday)
191 if not os.path.exists(dest_dir):
192 os.makedirs(dest_dir)
193
194 # Make sure dest_dir is empty (clean out last week's data).
195 cmd = "cd %s; rm -Rf %s_*_image*" % (dest_dir, self._weekday)
196 if dry_run:
197 print "CMD: %s" % cmd
198 else:
199 self._ce.RunCommand(cmd)
200
201 # Now create new tar files and copy them over.
202 labels = [ "test", "vanilla" ]
203 for label_name in labels:
204 if label_name == "test":
205 test_path = trybot_image
206 else:
207 test_path = vanilla_image
208 tar_file_name = "%s_%s_image.tar" % (self._weekday, label_name)
Han Shenfe054f12015-02-18 15:00:13 -0800209 cmd = ("cd %s; tar -cvf %s %s/chromiumos_test_image.bin; "
210 "cp %s %s/.") % (images_path,
211 tar_file_name,
212 test_path,
213 tar_file_name,
214 dest_dir)
cmtice46093e52014-12-09 14:59:16 -0800215 if dry_run:
216 print "CMD: %s" % cmd
217 tar_ret = 0
218 else:
219 tar_ret = self._ce.RunCommand(cmd)
220 if tar_ret:
221 self._l.LogOutput("Error while creating/copying test tar file(%s)."
222 % tar_file_name)
223
cmtice7f3190b2015-05-22 14:14:51 -0700224 def _SendEmail(self):
225 """Find email message generated by crosperf and send it."""
226 filename = os.path.join(self._reports_dir,
227 "msg_body.html")
228 if (os.path.exists(filename) and
229 os.path.exists(os.path.expanduser(MAIL_PROGRAM))):
Yunlian Jiang2f563562015-08-28 13:54:04 -0700230 email_title = "buildbot test results"
231 if self._patches_string == USE_LLVM_PATCH:
232 email_title = "buildbot llvm test results"
233 command = ('cat %s | %s -s "%s, %s" -team -html'
234 % (filename, MAIL_PROGRAM, email_title, self._board))
cmtice7f3190b2015-05-22 14:14:51 -0700235 self._ce.RunCommand(command)
cmtice46093e52014-12-09 14:59:16 -0800236
237 def DoAll(self):
238 """
239 Main function inside ToolchainComparator class.
240
241 Launch trybot, get image names, create crosperf experiment file, run
242 crosperf, and copy images into seven-day report directories.
243 """
cmticece5ffa42015-02-12 15:18:43 -0800244 date_str = datetime.date.today()
Yunlian Jiang3c6e4672015-08-24 15:58:22 -0700245 description = "master_%s_%s_%s" % (self._patches_string,
Han Shenfe054f12015-02-18 15:00:13 -0800246 self._build,
247 date_str)
cmtice46093e52014-12-09 14:59:16 -0800248 trybot_image = buildbot_utils.GetTrybotImage(self._chromeos_root,
249 self._build,
Yunlian Jiang3c6e4672015-08-24 15:58:22 -0700250 self._patches,
Luis Lozano8a68b2d2015-04-23 14:37:09 -0700251 description,
252 build_toolchain=True)
cmtice46093e52014-12-09 14:59:16 -0800253
254 vanilla_image = self._ParseVanillaImage(trybot_image)
255
256 print ("trybot_image: %s" % trybot_image)
257 print ("vanilla_image: %s" % vanilla_image)
cmticed54f9802015-02-05 11:04:11 -0800258 if len(trybot_image) == 0:
Luis Lozano7f20acb2015-11-04 17:15:08 -0800259 self._l.LogError("Unable to find trybot_image for %s!" % description)
260 return 1
cmticed54f9802015-02-05 11:04:11 -0800261 if len(vanilla_image) == 0:
Luis Lozano7f20acb2015-11-04 17:15:08 -0800262 self._l.LogError("Unable to find vanilla image for %s!" % description)
263 return 1
cmtice46093e52014-12-09 14:59:16 -0800264 if os.getlogin() == ROLE_ACCOUNT:
265 self._FinishSetup()
266
cmtice7f3190b2015-05-22 14:14:51 -0700267 self._TestImages(trybot_image, vanilla_image)
268 self._SendEmail()
Yunlian Jiang3c6e4672015-08-24 15:58:22 -0700269 if (self._patches_string == USE_NEXT_GCC_PATCH and
270 self._board in WEEKLY_REPORT_BOARDS):
Luis Lozano7f20acb2015-11-04 17:15:08 -0800271 # Only try to copy the image files if the test runs ran successfully.
272 self._CopyWeeklyReportFiles(trybot_image, vanilla_image)
cmtice46093e52014-12-09 14:59:16 -0800273 return 0
274
275
276def Main(argv):
277 """The main function."""
278
279 # Common initializations
280 command_executer.InitCommandExecuter()
281 parser = optparse.OptionParser()
282 parser.add_option("--remote",
283 dest="remote",
284 help="Remote machines to run tests on.")
285 parser.add_option("--board",
286 dest="board",
287 default="x86-zgb",
288 help="The target board.")
289 parser.add_option("--chromeos_root",
290 dest="chromeos_root",
291 help="The chromeos root from which to run tests.")
292 parser.add_option("--weekday", default="",
293 dest="weekday",
294 help="The day of the week for which to run tests.")
Yunlian Jiange52838c2015-08-20 14:32:37 -0700295 parser.add_option("--patch",
296 dest="patches",
297 help="The patches to use for the testing, "
298 "seprate the patch numbers with ',' "
299 "for more than one patches.")
Han Shen43494292015-09-14 10:26:40 -0700300 parser.add_option("--noschedv2",
301 dest="noschedv2",
Han Shen36413122015-08-28 11:05:40 -0700302 action="store_true",
303 default=False,
Han Shen43494292015-09-14 10:26:40 -0700304 help="Pass --noschedv2 to crosperf.")
Han Shen36413122015-08-28 11:05:40 -0700305
cmtice46093e52014-12-09 14:59:16 -0800306 options, _ = parser.parse_args(argv)
307 if not options.board:
308 print "Please give a board."
309 return 1
310 if not options.remote:
311 print "Please give at least one remote machine."
312 return 1
313 if not options.chromeos_root:
314 print "Please specify the ChromeOS root directory."
315 return 1
Yunlian Jiang76259e62015-08-21 08:44:31 -0700316 if options.patches:
Yunlian Jiang3c6e4672015-08-24 15:58:22 -0700317 patches = options.patches
318 else:
319 patches = USE_NEXT_GCC_PATCH
Yunlian Jiange52838c2015-08-20 14:32:37 -0700320
cmtice46093e52014-12-09 14:59:16 -0800321 fc = ToolchainComparator(options.board, options.remote,
Han Shen36413122015-08-28 11:05:40 -0700322 options.chromeos_root, options.weekday, patches,
Han Shen43494292015-09-14 10:26:40 -0700323 options.noschedv2)
cmtice46093e52014-12-09 14:59:16 -0800324 return fc.DoAll()
325
326
327if __name__ == "__main__":
328 retval = Main(sys.argv)
329 sys.exit(retval)