buildbot_test_toolchains.py revision 7f20acb9c9036015a665a14f27633c639e9b9d91
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 18 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'. 25USE_NEXT_GCC_PATCH = "230260" 26 27# CL that uses LLVM to build the peppy image. 28USE_LLVM_PATCH = "295217" 29 30# The boards on which we run weekly reports 31WEEKLY_REPORT_BOARDS = ["lumpy"] 32 33CROSTC_ROOT = "/usr/local/google/crostc" 34ROLE_ACCOUNT = "mobiletc-prebuild" 35TOOLCHAIN_DIR = os.path.dirname(os.path.realpath(__file__)) 36MAIL_PROGRAM = "~/var/bin/mail-sheriff" 37WEEKLY_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") 40 41class ToolchainComparator(): 42 """ 43 Class for doing the nightly tests work. 44 """ 45 46 def __init__(self, board, remotes, chromeos_root, weekday, patches, noschedv2=False): 47 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 54 self._patches = patches.split(',') 55 self._patches_string = '_'.join(str(p) for p in self._patches) 56 self._noschedv2 = noschedv2 57 58 if not weekday: 59 self._weekday = time.strftime("%a") 60 else: 61 self._weekday = weekday 62 timestamp = datetime.datetime.strftime(datetime.datetime.now(), 63 "%Y-%m-%d_%H:%M:%S") 64 self._reports_dir = os.path.join(NIGHTLY_TESTS_DIR, 65 "%s.%s" % (timestamp, board), 66 ) 67 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 81 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) 90 if ret_val != 0: 91 raise RuntimeError("chmod for testing_rsa failed") 92 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 103 104 compiler_string = "gcc" 105 if self._patches_string == USE_LLVM_PATCH: 106 experiment_file_name = "%s_llvm_experiment.txt" % self._board 107 compiler_string = "llvm" 108 109 experiment_file = os.path.join (experiment_file_dir, 110 experiment_file_name) 111 experiment_header = """ 112 board: %s 113 remote: %s 114 retries: 1 115 """ % (self._board, self._remotes) 116 experiment_tests = """ 117 benchmark: all_toolchain_perf_pure_telemetry { 118 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 131 compiler: gcc 132 } 133 """ % (self._chromeos_root, vanilla_image) 134 print >> f, official_image 135 136 label_string = "%s_trybot_image" % compiler_string 137 if USE_NEXT_GCC_PATCH in self._patches: 138 label_string = "gcc_next_trybot_image" 139 140 experiment_image = """ 141 %s { 142 chromeos_root: %s 143 build: %s 144 compiler: %s 145 } 146 """ % (label_string, self._chromeos_root, trybot_image, 147 compiler_string) 148 print >> f, experiment_image 149 150 crosperf = os.path.join(TOOLCHAIN_DIR, 151 "crosperf", 152 "crosperf") 153 noschedv2_opts = '--noschedv2' if self._noschedv2 else '' 154 command = ("{crosperf} --no_email=True --results_dir={r_dir} " 155 "--json_report=True {noschedv2_opts} {exp_file}").format( 156 crosperf=crosperf, 157 r_dir=self._reports_dir, 158 noschedv2_opts=noschedv2_opts, 159 exp_file=experiment_file) 160 161 ret = self._ce.RunCommand(command) 162 if ret != 0: 163 raise RuntimeError("Couldn't run crosperf!") 164 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) 168 return 169 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) 209 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) 215 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 224 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))): 230 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)) 235 self._ce.RunCommand(command) 236 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 """ 244 date_str = datetime.date.today() 245 description = "master_%s_%s_%s" % (self._patches_string, 246 self._build, 247 date_str) 248 trybot_image = buildbot_utils.GetTrybotImage(self._chromeos_root, 249 self._build, 250 self._patches, 251 description, 252 build_toolchain=True) 253 254 vanilla_image = self._ParseVanillaImage(trybot_image) 255 256 print ("trybot_image: %s" % trybot_image) 257 print ("vanilla_image: %s" % vanilla_image) 258 if len(trybot_image) == 0: 259 self._l.LogError("Unable to find trybot_image for %s!" % description) 260 return 1 261 if len(vanilla_image) == 0: 262 self._l.LogError("Unable to find vanilla image for %s!" % description) 263 return 1 264 if os.getlogin() == ROLE_ACCOUNT: 265 self._FinishSetup() 266 267 self._TestImages(trybot_image, vanilla_image) 268 self._SendEmail() 269 if (self._patches_string == USE_NEXT_GCC_PATCH and 270 self._board in WEEKLY_REPORT_BOARDS): 271 # Only try to copy the image files if the test runs ran successfully. 272 self._CopyWeeklyReportFiles(trybot_image, vanilla_image) 273 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.") 295 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.") 300 parser.add_option("--noschedv2", 301 dest="noschedv2", 302 action="store_true", 303 default=False, 304 help="Pass --noschedv2 to crosperf.") 305 306 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 316 if options.patches: 317 patches = options.patches 318 else: 319 patches = USE_NEXT_GCC_PATCH 320 321 fc = ToolchainComparator(options.board, options.remote, 322 options.chromeos_root, options.weekday, patches, 323 options.noschedv2) 324 return fc.DoAll() 325 326 327if __name__ == "__main__": 328 retval = Main(sys.argv) 329 sys.exit(retval) 330