buildbot_test_toolchains.py revision ddde50532281f7f796dd7dc44b562b29d25ab381
1#!/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. 13import datetime 14import 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'. 26USE_NEXT_GCC_PATCH = "230260" 27 28# CL that uses LLVM to build the peppy image. 29USE_LLVM_PATCH = "295217" 30 31# The boards on which we run weekly reports 32WEEKLY_REPORT_BOARDS = ["lumpy"] 33 34CROSTC_ROOT = "/usr/local/google/crostc" 35ROLE_ACCOUNT = "mobiletc-prebuild" 36TOOLCHAIN_DIR = os.path.dirname(os.path.realpath(__file__)) 37MAIL_PROGRAM = "~/var/bin/mail-sheriff" 38WEEKLY_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") 41 42class ToolchainComparator(): 43 """ 44 Class for doing the nightly tests work. 45 """ 46 47 def __init__(self, board, remotes, chromeos_root, weekday, patches, noschedv2=False): 48 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 55 self._patches = patches.split(',') 56 self._patches_string = '_'.join(str(p) for p in self._patches) 57 self._noschedv2 = noschedv2 58 59 if not weekday: 60 self._weekday = time.strftime("%a") 61 else: 62 self._weekday = weekday 63 timestamp = datetime.datetime.strftime(datetime.datetime.now(), 64 "%Y-%m-%d_%H:%M:%S") 65 self._reports_dir = os.path.join(NIGHTLY_TESTS_DIR, 66 "%s.%s" % (timestamp, board), 67 ) 68 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 82 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) 91 if ret_val != 0: 92 raise RuntimeError("chmod for testing_rsa failed") 93 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 104 105 compiler_string = "gcc" 106 if self._patches_string == USE_LLVM_PATCH: 107 experiment_file_name = "%s_llvm_experiment.txt" % self._board 108 compiler_string = "llvm" 109 110 experiment_file = os.path.join (experiment_file_dir, 111 experiment_file_name) 112 experiment_header = """ 113 board: %s 114 remote: %s 115 retries: 1 116 """ % (self._board, self._remotes) 117 experiment_tests = """ 118 benchmark: all_toolchain_perf { 119 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 132 compiler: gcc 133 } 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 141 compiler: %s 142 } 143 """ % (self._chromeos_root, trybot_image, compiler_string) 144 print >> f, experiment_image 145 146 crosperf = os.path.join(TOOLCHAIN_DIR, 147 "crosperf", 148 "crosperf") 149 noschedv2_opts = '--noschedv2' if self._noschedv2 else '' 150 command = ("{crosperf} --no_email=True --results_dir={r_dir} " 151 "--json_report=True {noschedv2_opts} {exp_file}").format( 152 crosperf=crosperf, 153 r_dir=self._reports_dir, 154 noschedv2_opts=noschedv2_opts, 155 exp_file=experiment_file) 156 157 ret = self._ce.RunCommand(command) 158 if ret != 0: 159 raise RuntimeError("Couldn't run crosperf!") 160 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) 164 return 165 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) 205 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) 211 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 220 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))): 226 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)) 231 self._ce.RunCommand(command) 232 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 """ 240 date_str = datetime.date.today() 241 description = "master_%s_%s_%s" % (self._patches_string, 242 self._build, 243 date_str) 244 trybot_image = buildbot_utils.GetTrybotImage(self._chromeos_root, 245 self._build, 246 self._patches, 247 description, 248 build_toolchain=True) 249 250 vanilla_image = self._ParseVanillaImage(trybot_image) 251 252 print ("trybot_image: %s" % trybot_image) 253 print ("vanilla_image: %s" % vanilla_image) 254 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 260 if os.getlogin() == ROLE_ACCOUNT: 261 self._FinishSetup() 262 263 self._TestImages(trybot_image, vanilla_image) 264 self._SendEmail() 265 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) 269 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.") 291 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.") 296 parser.add_option("--noschedv2", 297 dest="noschedv2", 298 action="store_true", 299 default=False, 300 help="Pass --noschedv2 to crosperf.") 301 302 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 312 if options.patches: 313 patches = options.patches 314 else: 315 patches = USE_NEXT_GCC_PATCH 316 317 fc = ToolchainComparator(options.board, options.remote, 318 options.chromeos_root, options.weekday, patches, 319 options.noschedv2) 320 return fc.DoAll() 321 322 323if __name__ == "__main__": 324 retval = Main(sys.argv) 325 sys.exit(retval) 326