blob: 578312e2cee12c69ec8a2198959660d5fb34b9ea [file] [log] [blame]
asharif96f59692013-02-16 03:13:36 +00001#!/usr/bin/python
2
3# Script to test different toolchains against ChromeOS benchmarks.
4import optparse
5import os
6import sys
7import build_chromeos
8import setup_chromeos
cmtice94bc4702014-05-29 16:29:04 -07009import time
asharif96f59692013-02-16 03:13:36 +000010from utils import command_executer
11from utils import misc
12from utils import logger
13
14
cmtice94bc4702014-05-29 16:29:04 -070015WEEKLY_REPORTS_ROOT="/usr/local/google/crostc/weekly_test_data"
cmtice23130bd2014-07-15 11:19:29 -070016AFDO_BOARDS = ["butterfly", "lumpy", "stumpy", "stout", "parrot", "parrot_ivb"]
cmtice94bc4702014-05-29 16:29:04 -070017
asharif96f59692013-02-16 03:13:36 +000018class GCCConfig(object):
19 def __init__(self, githash):
20 self.githash = githash
21
22
23class ToolchainConfig:
24 def __init__(self, gcc_config=None, binutils_config=None):
25 self.gcc_config = gcc_config
26
27
28class ChromeOSCheckout(object):
29 def __init__(self, board, chromeos_root):
30 self._board = board
31 self._chromeos_root = chromeos_root
32 self._ce = command_executer.GetCommandExecuter()
33 self._l = logger.GetLogger()
cmtice56fb7162014-06-18 11:32:15 -070034 self._build_num = None
asharif96f59692013-02-16 03:13:36 +000035
asharif3e38de02013-02-19 19:34:59 +000036 def _DeleteChroot(self):
asharif87414272013-02-19 19:58:45 +000037 command = "cd %s; cros_sdk --delete" % self._chromeos_root
asharif3e38de02013-02-19 19:34:59 +000038 return self._ce.RunCommand(command)
39
asharif67973582013-02-19 20:19:40 +000040 def _DeleteCcahe(self):
41 # crosbug.com/34956
42 command = "sudo rm -rf %s" % os.path.join(self._chromeos_root, ".cache")
43 return self._ce.RunCommand(command)
44
cmtice56fb7162014-06-18 11:32:15 -070045 def _GetBuildNumber(self):
46 """ This function assumes a ChromeOS image has been built in the chroot.
47 It translates the 'latest' symlink in the
48 <chroot>/src/build/images/<board> directory, to find the actual
49 ChromeOS build number for the image that was built. For example, if
50 src/build/image/lumpy/latest -> R37-5982.0.2014_06_23_0454-a1, then
51 This function would parse it out and assign 'R37-5982' to self._build_num.
52 This is used to determine the official, vanilla build to use for
53 comparison tests.
54 """
55 # Get the path to 'latest'
56 sym_path = os.path.join (misc.GetImageDir(self._chromeos_root,
57 self._board),
58 "latest")
59 # Translate the symlink to its 'real' path.
60 real_path = os.path.realpath(sym_path)
61 # Break up the path and get the last piece
62 # (e.g. 'R37-5982.0.2014_06_23_0454-a1"
63 path_pieces = real_path.split("/")
64 last_piece = path_pieces[-1]
65 # Break this piece into the image number + other pieces, and get the
66 # image number [ 'R37-5982', '0', '2014_06_23_0454-a1']
67 image_parts = last_piece.split(".")
68 self._build_num = image_parts[0]
69
asharif96f59692013-02-16 03:13:36 +000070 def _BuildAndImage(self, label=""):
71 if (not label or
72 not misc.DoesLabelExist(self._chromeos_root, self._board, label)):
73 build_chromeos_args = [build_chromeos.__file__,
74 "--chromeos_root=%s" % self._chromeos_root,
75 "--board=%s" % self._board,
76 "--rebuild"]
asharife6b72fe2013-02-19 19:58:18 +000077 if self._public:
78 build_chromeos_args.append("--env=USE=-chrome_internal")
cmtice56fb7162014-06-18 11:32:15 -070079
cmtice23130bd2014-07-15 11:19:29 -070080 if self._board in AFDO_BOARDS:
81 build_chromeos_args.append("--env=USE=afdo_use")
82
asharif96f59692013-02-16 03:13:36 +000083 ret = build_chromeos.Main(build_chromeos_args)
84 if ret:
85 raise Exception("Couldn't build ChromeOS!")
cmtice56fb7162014-06-18 11:32:15 -070086
87 if not self._build_num:
88 self._GetBuildNumber()
89 # Check to see if we need to create the symbolic link for the vanilla
90 # image, and do so if appropriate.
91 if not misc.DoesLabelExist(self._chromeos_root, self._board, "vanilla"):
92 build_name = "%s-release/%s.0.0" % (self._board, self._build_num)
93 full_vanilla_path = os.path.join (os.getcwd(), self._chromeos_root,
94 'chroot/tmp', build_name)
95 misc.LabelLatestImage(self._chromeos_root, self._board, label,
96 full_vanilla_path)
97 else:
asharif96f59692013-02-16 03:13:36 +000098 misc.LabelLatestImage(self._chromeos_root, self._board, label)
99 return label
100
cmtice56fb7162014-06-18 11:32:15 -0700101 def _SetupBoard(self, env_dict, usepkg_flag, clobber_flag):
asharif96f59692013-02-16 03:13:36 +0000102 env_string = misc.GetEnvStringFromDict(env_dict)
103 command = ("%s %s" %
104 (env_string,
105 misc.GetSetupBoardCommand(self._board,
cmtice56fb7162014-06-18 11:32:15 -0700106 usepkg=usepkg_flag,
107 force=clobber_flag)))
asharif96f59692013-02-16 03:13:36 +0000108 ret = self._ce.ChrootRunCommand(self._chromeos_root,
109 command)
cmtice56fb7162014-06-18 11:32:15 -0700110 error_str = "Could not setup board: '%s'" % command
111 assert ret == 0, error_str
asharif96f59692013-02-16 03:13:36 +0000112
113 def _UnInstallToolchain(self):
114 command = ("sudo CLEAN_DELAY=0 emerge -C cross-%s/gcc" %
115 misc.GetCtargetFromBoard(self._board,
116 self._chromeos_root))
117 ret = self._ce.ChrootRunCommand(self._chromeos_root,
118 command)
119 if ret:
120 raise Exception("Couldn't uninstall the toolchain!")
121
122 def _CheckoutChromeOS(self):
123 # TODO(asharif): Setup a fixed ChromeOS version (quarterly snapshot).
124 if not os.path.exists(self._chromeos_root):
125 setup_chromeos_args = [setup_chromeos.__file__,
Caroline Ticec35909e2013-10-02 17:13:13 -0700126 "--dir=%s" % self._chromeos_root]
asharife6b72fe2013-02-19 19:58:18 +0000127 if self._public:
128 setup_chromeos_args.append("--public")
asharif5fe40e22013-02-19 19:58:50 +0000129 ret = setup_chromeos.Main(setup_chromeos_args)
130 if ret:
131 raise Exception("Couldn't run setup_chromeos!")
asharif96f59692013-02-16 03:13:36 +0000132
Caroline Ticec35909e2013-10-02 17:13:13 -0700133
asharif96f59692013-02-16 03:13:36 +0000134 def _BuildToolchain(self, config):
cmtice56fb7162014-06-18 11:32:15 -0700135 # Call setup_board for basic, vanilla setup.
136 self._SetupBoard({}, usepkg_flag=True, clobber_flag=False)
137 # Now uninstall the vanilla compiler and setup/build our custom
138 # compiler.
asharif96f59692013-02-16 03:13:36 +0000139 self._UnInstallToolchain()
cmtice56fb7162014-06-18 11:32:15 -0700140 envdict = {"USE": "git_gcc",
141 "GCC_GITHASH": config.gcc_config.githash,
142 "EMERGE_DEFAULT_OPTS": "--exclude=gcc"}
143 self._SetupBoard(envdict, usepkg_flag=False, clobber_flag=False)
asharif96f59692013-02-16 03:13:36 +0000144
145
146class ToolchainComparator(ChromeOSCheckout):
asharif58a8c9f2013-02-19 20:42:43 +0000147 def __init__(self, board, remotes, configs, clean, public, force_mismatch):
asharif96f59692013-02-16 03:13:36 +0000148 self._board = board
149 self._remotes = remotes
150 self._chromeos_root = "chromeos"
151 self._configs = configs
asharif3e38de02013-02-19 19:34:59 +0000152 self._clean = clean
asharife6b72fe2013-02-19 19:58:18 +0000153 self._public = public
asharif58a8c9f2013-02-19 20:42:43 +0000154 self._force_mismatch = force_mismatch
asharif96f59692013-02-16 03:13:36 +0000155 self._ce = command_executer.GetCommandExecuter()
156 self._l = logger.GetLogger()
157 ChromeOSCheckout.__init__(self, board, self._chromeos_root)
158
cmticea6255d02014-01-10 10:27:22 -0800159
160 def _FinishSetup(self):
161 # Get correct .boto file
162 current_dir = os.getcwd()
163 src = "/home/mobiletc-prebuild/.boto"
164 dest = os.path.join(current_dir, self._chromeos_root,
165 "src/private-overlays/chromeos-overlay/"
166 "googlestorage_account.boto")
167 # Copy the file to the correct place
168 copy_cmd = "cp %s %s" % (src, dest)
169 retval = self._ce.RunCommand(copy_cmd)
170 if retval:
171 raise Exception("Couldn't copy .boto file for google storage.")
172
173 # Fix protections on ssh key
174 command = ("chmod 600 /var/cache/chromeos-cache/distfiles/target"
175 "/chrome-src-internal/src/third_party/chromite/ssh_keys"
176 "/testing_rsa")
177 retval = self._ce.ChrootRunCommand(self._chromeos_root, command)
178 if retval:
179 raise Exception("chmod for testing_rsa failed")
180
asharif96f59692013-02-16 03:13:36 +0000181 def _TestLabels(self, labels):
182 experiment_file = "toolchain_experiment.txt"
asharif58a8c9f2013-02-19 20:42:43 +0000183 image_args = ""
184 if self._force_mismatch:
asharif0b5d5c82013-02-19 20:42:56 +0000185 image_args = "--force-mismatch"
asharif96f59692013-02-16 03:13:36 +0000186 experiment_header = """
187 board: %s
188 remote: %s
189 """ % (self._board, self._remotes)
190 experiment_tests = """
cmtice04403882013-11-04 16:38:37 -0500191 benchmark: all_perfv2 {
192 suite: telemetry_Crosperf
cmtice6de7f8f2014-03-14 14:08:21 -0700193 iterations: 3
asharif96f59692013-02-16 03:13:36 +0000194 }
195 """
196 with open(experiment_file, "w") as f:
197 print >>f, experiment_header
198 print >>f, experiment_tests
199 for label in labels:
200 # TODO(asharif): Fix crosperf so it accepts labels with symbols
201 crosperf_label = label
202 crosperf_label = crosperf_label.replace("-", "minus")
203 crosperf_label = crosperf_label.replace("+", "plus")
asharife4a5a8f2013-02-19 20:19:33 +0000204 crosperf_label = crosperf_label.replace(".", "")
cmtice56fb7162014-06-18 11:32:15 -0700205
206 # Use the official build instead of building vanilla ourselves.
207 if label == "vanilla":
208 build_name = '%s-release/%s.0.0' % (self._board, self._build_num)
209
210 # Now add 'official build' to test file.
211 official_image = """
212 official_image {
213 chromeos_root: %s
214 build: %s
215 }
216 """ % (self._chromeos_root, build_name)
217 print >>f, official_image
218
cmtice94bc4702014-05-29 16:29:04 -0700219 else:
cmtice56fb7162014-06-18 11:32:15 -0700220 experiment_image = """
221 %s {
222 chromeos_image: %s
223 image_args: %s
224 }
225 """ % (crosperf_label,
226 os.path.join(misc.GetImageDir(self._chromeos_root,
227 self._board),
228 label, "chromiumos_test_image.bin"),
229 image_args)
230 print >>f, experiment_image
231
asharif96f59692013-02-16 03:13:36 +0000232 crosperf = os.path.join(os.path.dirname(__file__),
233 "crosperf",
234 "crosperf")
asharifb2cd6342013-02-19 19:42:57 +0000235 command = "%s --email=c-compiler-chrome %s" % (crosperf, experiment_file)
asharif96f59692013-02-16 03:13:36 +0000236 ret = self._ce.RunCommand(command)
237 if ret:
238 raise Exception("Couldn't run crosperf!")
cmtice56fb7162014-06-18 11:32:15 -0700239 return ret
240
241
242 def _CopyWeeklyReportFiles(self, labels):
243 """Create tar files of the custom and official images and copy them
244 to the weekly reports directory, so they exist when the weekly report
245 gets generated. IMPORTANT NOTE: This function must run *after*
246 crosperf has been run; otherwise the vanilla images will not be there.
247 """
248 images_path = os.path.join(os.path.realpath(self._chromeos_root),
249 "src/build/images", self._board)
250 weekday = time.strftime("%a")
251 data_dir = os.path.join(WEEKLY_REPORTS_ROOT, self._board)
252 dest_dir = os.path.join (data_dir, weekday)
253 if not os.path.exists(dest_dir):
254 os.makedirs(dest_dir)
cmtice4536ef62014-07-08 11:17:21 -0700255 # Make sure dest_dir is empty (clean out last week's data).
256 cmd = "cd %s; rm -Rf %s_*_image*" % (dest_dir, weekday)
257 self._ce.RunCommand(cmd)
258 # Now create new tar files and copy them over.
cmtice56fb7162014-06-18 11:32:15 -0700259 for l in labels:
260 test_path = os.path.join(images_path, l)
261 if os.path.exists(test_path):
262 if l != "vanilla":
263 label_name = "test"
264 else:
265 label_name = "vanilla"
266 tar_file_name = "%s_%s_image.tar" % (weekday, label_name)
267 cmd = "cd %s; tar -cvf %s %s/*; cp %s %s/." % (images_path,
268 tar_file_name,
269 l, tar_file_name,
270 dest_dir)
271 tar_ret = self._ce.RunCommand(cmd)
272 if tar_ret:
273 self._l.LogOutput("Error while creating/copying test tar file(%s)."
274 % tar_file_name)
275
asharif96f59692013-02-16 03:13:36 +0000276
277 def DoAll(self):
278 self._CheckoutChromeOS()
asharif96f59692013-02-16 03:13:36 +0000279 labels = []
cmtice56fb7162014-06-18 11:32:15 -0700280 labels.append("vanilla")
asharif96f59692013-02-16 03:13:36 +0000281 for config in self._configs:
282 label = misc.GetFilenameFromString(config.gcc_config.githash)
283 if (not misc.DoesLabelExist(self._chromeos_root,
284 self._board,
285 label)):
286 self._BuildToolchain(config)
287 label = self._BuildAndImage(label)
288 labels.append(label)
cmticea6255d02014-01-10 10:27:22 -0800289 self._FinishSetup()
cmtice56fb7162014-06-18 11:32:15 -0700290 if not self._TestLabels(labels):
291 # Only try to copy the image files if the test runs ran successfully.
292 self._CopyWeeklyReportFiles(labels)
asharif3e38de02013-02-19 19:34:59 +0000293 if self._clean:
294 ret = self._DeleteChroot()
295 if ret: return ret
asharif67973582013-02-19 20:19:40 +0000296 ret = self._DeleteCcahe()
297 if ret: return ret
asharif96f59692013-02-16 03:13:36 +0000298 return 0
299
300
301def Main(argv):
302 """The main function."""
303 # Common initializations
304### command_executer.InitCommandExecuter(True)
305 command_executer.InitCommandExecuter()
306 parser = optparse.OptionParser()
307 parser.add_option("--remote",
308 dest="remote",
309 help="Remote machines to run tests on.")
310 parser.add_option("--board",
311 dest="board",
312 default="x86-zgb",
313 help="The target board.")
314 parser.add_option("--githashes",
315 dest="githashes",
316 default="master",
317 help="The gcc githashes to test.")
asharif3e38de02013-02-19 19:34:59 +0000318 parser.add_option("--clean",
319 dest="clean",
320 default=False,
321 action="store_true",
322 help="Clean the chroot after testing.")
asharife6b72fe2013-02-19 19:58:18 +0000323 parser.add_option("--public",
324 dest="public",
325 default=False,
326 action="store_true",
327 help="Use the public checkout/build.")
asharif58a8c9f2013-02-19 20:42:43 +0000328 parser.add_option("--force-mismatch",
329 dest="force_mismatch",
330 default="",
331 help="Force the image regardless of board mismatch")
asharif96f59692013-02-16 03:13:36 +0000332 options, _ = parser.parse_args(argv)
333 if not options.board:
334 print "Please give a board."
335 return 1
336 if not options.remote:
337 print "Please give at least one remote machine."
338 return 1
339 toolchain_configs = []
340 for githash in options.githashes.split(","):
341 gcc_config = GCCConfig(githash=githash)
342 toolchain_config = ToolchainConfig(gcc_config=gcc_config)
343 toolchain_configs.append(toolchain_config)
asharif3e38de02013-02-19 19:34:59 +0000344 fc = ToolchainComparator(options.board, options.remote, toolchain_configs,
asharif58a8c9f2013-02-19 20:42:43 +0000345 options.clean, options.public,
346 options.force_mismatch)
asharif96f59692013-02-16 03:13:36 +0000347 return fc.DoAll()
348
349
350if __name__ == "__main__":
351 retval = Main(sys.argv)
352 sys.exit(retval)