blob: 35e6a40a1dbf6090cd098901d8bb58d921c773c7 [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
137 experiment_image = """
138 test_image {
139 chromeos_root: %s
140 build: %s
Caroline Ticeddde5052015-09-23 09:43:35 -0700141 compiler: %s
cmtice46093e52014-12-09 14:59:16 -0800142 }
Caroline Ticeddde5052015-09-23 09:43:35 -0700143 """ % (self._chromeos_root, trybot_image, compiler_string)
cmtice46093e52014-12-09 14:59:16 -0800144 print >> f, experiment_image
145
146 crosperf = os.path.join(TOOLCHAIN_DIR,
147 "crosperf",
148 "crosperf")
Han Shen43494292015-09-14 10:26:40 -0700149 noschedv2_opts = '--noschedv2' if self._noschedv2 else ''
Han Shen36413122015-08-28 11:05:40 -0700150 command = ("{crosperf} --no_email=True --results_dir={r_dir} "
Han Shen43494292015-09-14 10:26:40 -0700151 "--json_report=True {noschedv2_opts} {exp_file}").format(
Han Shen36413122015-08-28 11:05:40 -0700152 crosperf=crosperf,
153 r_dir=self._reports_dir,
Han Shen43494292015-09-14 10:26:40 -0700154 noschedv2_opts=noschedv2_opts,
Han Shen36413122015-08-28 11:05:40 -0700155 exp_file=experiment_file)
cmticeaa700b02015-06-12 13:26:47 -0700156
cmtice46093e52014-12-09 14:59:16 -0800157 ret = self._ce.RunCommand(command)
cmtice7f3190b2015-05-22 14:14:51 -0700158 if ret != 0:
159 raise RuntimeError("Couldn't run crosperf!")
Caroline Ticeebbc3da2015-09-03 10:27:20 -0700160 else:
161 # Copy json report to pending archives directory.
162 command = "cp %s/*.json %s/." % (self._reports_dir, PENDING_ARCHIVES_DIR)
163 ret = self._ce.RunCommand(command)
cmtice7f3190b2015-05-22 14:14:51 -0700164 return
cmtice46093e52014-12-09 14:59:16 -0800165
166 def _CopyWeeklyReportFiles(self, trybot_image, vanilla_image):
167 """
168 Put files in place for running seven-day reports.
169
170 Create tar files of the custom and official images and copy them
171 to the weekly reports directory, so they exist when the weekly report
172 gets generated. IMPORTANT NOTE: This function must run *after*
173 crosperf has been run; otherwise the vanilla images will not be there.
174 """
175
176 dry_run = False
177 if (os.getlogin() != ROLE_ACCOUNT):
178 self._l.LogOutput("Running this from non-role account; not copying "
179 "tar files for weekly reports.")
180 dry_run = True
181
182 images_path = os.path.join(os.path.realpath(self._chromeos_root),
183 "chroot/tmp")
184
185 data_dir = os.path.join(WEEKLY_REPORTS_ROOT, self._board)
186 dest_dir = os.path.join (data_dir, self._weekday)
187 if not os.path.exists(dest_dir):
188 os.makedirs(dest_dir)
189
190 # Make sure dest_dir is empty (clean out last week's data).
191 cmd = "cd %s; rm -Rf %s_*_image*" % (dest_dir, self._weekday)
192 if dry_run:
193 print "CMD: %s" % cmd
194 else:
195 self._ce.RunCommand(cmd)
196
197 # Now create new tar files and copy them over.
198 labels = [ "test", "vanilla" ]
199 for label_name in labels:
200 if label_name == "test":
201 test_path = trybot_image
202 else:
203 test_path = vanilla_image
204 tar_file_name = "%s_%s_image.tar" % (self._weekday, label_name)
Han Shenfe054f12015-02-18 15:00:13 -0800205 cmd = ("cd %s; tar -cvf %s %s/chromiumos_test_image.bin; "
206 "cp %s %s/.") % (images_path,
207 tar_file_name,
208 test_path,
209 tar_file_name,
210 dest_dir)
cmtice46093e52014-12-09 14:59:16 -0800211 if dry_run:
212 print "CMD: %s" % cmd
213 tar_ret = 0
214 else:
215 tar_ret = self._ce.RunCommand(cmd)
216 if tar_ret:
217 self._l.LogOutput("Error while creating/copying test tar file(%s)."
218 % tar_file_name)
219
cmtice7f3190b2015-05-22 14:14:51 -0700220 def _SendEmail(self):
221 """Find email message generated by crosperf and send it."""
222 filename = os.path.join(self._reports_dir,
223 "msg_body.html")
224 if (os.path.exists(filename) and
225 os.path.exists(os.path.expanduser(MAIL_PROGRAM))):
Yunlian Jiang2f563562015-08-28 13:54:04 -0700226 email_title = "buildbot test results"
227 if self._patches_string == USE_LLVM_PATCH:
228 email_title = "buildbot llvm test results"
229 command = ('cat %s | %s -s "%s, %s" -team -html'
230 % (filename, MAIL_PROGRAM, email_title, self._board))
cmtice7f3190b2015-05-22 14:14:51 -0700231 self._ce.RunCommand(command)
cmtice46093e52014-12-09 14:59:16 -0800232
233 def DoAll(self):
234 """
235 Main function inside ToolchainComparator class.
236
237 Launch trybot, get image names, create crosperf experiment file, run
238 crosperf, and copy images into seven-day report directories.
239 """
cmticece5ffa42015-02-12 15:18:43 -0800240 date_str = datetime.date.today()
Yunlian Jiang3c6e4672015-08-24 15:58:22 -0700241 description = "master_%s_%s_%s" % (self._patches_string,
Han Shenfe054f12015-02-18 15:00:13 -0800242 self._build,
243 date_str)
cmtice46093e52014-12-09 14:59:16 -0800244 trybot_image = buildbot_utils.GetTrybotImage(self._chromeos_root,
245 self._build,
Yunlian Jiang3c6e4672015-08-24 15:58:22 -0700246 self._patches,
Luis Lozano8a68b2d2015-04-23 14:37:09 -0700247 description,
248 build_toolchain=True)
cmtice46093e52014-12-09 14:59:16 -0800249
250 vanilla_image = self._ParseVanillaImage(trybot_image)
251
252 print ("trybot_image: %s" % trybot_image)
253 print ("vanilla_image: %s" % vanilla_image)
cmticed54f9802015-02-05 11:04:11 -0800254 if len(trybot_image) == 0:
255 self._l.LogError("Unable to find trybot_image for %s!" % description)
256 return 1
257 if len(vanilla_image) == 0:
258 self._l.LogError("Unable to find vanilla image for %s!" % description)
259 return 1
cmtice46093e52014-12-09 14:59:16 -0800260 if os.getlogin() == ROLE_ACCOUNT:
261 self._FinishSetup()
262
cmtice7f3190b2015-05-22 14:14:51 -0700263 self._TestImages(trybot_image, vanilla_image)
264 self._SendEmail()
Yunlian Jiang3c6e4672015-08-24 15:58:22 -0700265 if (self._patches_string == USE_NEXT_GCC_PATCH and
266 self._board in WEEKLY_REPORT_BOARDS):
267 # Only try to copy the image files if the test runs ran successfully.
268 self._CopyWeeklyReportFiles(trybot_image, vanilla_image)
cmtice46093e52014-12-09 14:59:16 -0800269 return 0
270
271
272def Main(argv):
273 """The main function."""
274
275 # Common initializations
276 command_executer.InitCommandExecuter()
277 parser = optparse.OptionParser()
278 parser.add_option("--remote",
279 dest="remote",
280 help="Remote machines to run tests on.")
281 parser.add_option("--board",
282 dest="board",
283 default="x86-zgb",
284 help="The target board.")
285 parser.add_option("--chromeos_root",
286 dest="chromeos_root",
287 help="The chromeos root from which to run tests.")
288 parser.add_option("--weekday", default="",
289 dest="weekday",
290 help="The day of the week for which to run tests.")
Yunlian Jiange52838c2015-08-20 14:32:37 -0700291 parser.add_option("--patch",
292 dest="patches",
293 help="The patches to use for the testing, "
294 "seprate the patch numbers with ',' "
295 "for more than one patches.")
Han Shen43494292015-09-14 10:26:40 -0700296 parser.add_option("--noschedv2",
297 dest="noschedv2",
Han Shen36413122015-08-28 11:05:40 -0700298 action="store_true",
299 default=False,
Han Shen43494292015-09-14 10:26:40 -0700300 help="Pass --noschedv2 to crosperf.")
Han Shen36413122015-08-28 11:05:40 -0700301
cmtice46093e52014-12-09 14:59:16 -0800302 options, _ = parser.parse_args(argv)
303 if not options.board:
304 print "Please give a board."
305 return 1
306 if not options.remote:
307 print "Please give at least one remote machine."
308 return 1
309 if not options.chromeos_root:
310 print "Please specify the ChromeOS root directory."
311 return 1
Yunlian Jiang76259e62015-08-21 08:44:31 -0700312 if options.patches:
Yunlian Jiang3c6e4672015-08-24 15:58:22 -0700313 patches = options.patches
314 else:
315 patches = USE_NEXT_GCC_PATCH
Yunlian Jiange52838c2015-08-20 14:32:37 -0700316
cmtice46093e52014-12-09 14:59:16 -0800317 fc = ToolchainComparator(options.board, options.remote,
Han Shen36413122015-08-28 11:05:40 -0700318 options.chromeos_root, options.weekday, patches,
Han Shen43494292015-09-14 10:26:40 -0700319 options.noschedv2)
cmtice46093e52014-12-09 14:59:16 -0800320 return fc.DoAll()
321
322
323if __name__ == "__main__":
324 retval = Main(sys.argv)
325 sys.exit(retval)