buildbot_test_toolchains.py revision f456b2035aec47012d7d111b0c5e21a3319823c0
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 28WEEKLY_REPORTS_ROOT = "/usr/local/google/crostc/weekly_test_data" 29ROLE_ACCOUNT = "mobiletc-prebuild" 30TOOLCHAIN_DIR = os.path.dirname(os.path.realpath(__file__)) 31MAIL_PROGRAM = "~/var/bin/mail-sheriff" 32 33class ToolchainComparator(): 34 """ 35 Class for doing the nightly tests work. 36 """ 37 38 def __init__(self, board, remotes, chromeos_root, weekday): 39 self._board = board 40 self._remotes = remotes 41 self._chromeos_root = chromeos_root 42 self._base_dir = os.getcwd() 43 self._ce = command_executer.GetCommandExecuter() 44 self._l = logger.GetLogger() 45 self._build = "%s-release" % board 46 if not weekday: 47 self._weekday = time.strftime("%a") 48 else: 49 self._weekday = weekday 50 timestamp = datetime.datetime.strftime(datetime.datetime.now(), 51 "%Y-%m-%d_%H:%M:%S") 52 self._reports_dir = os.path.join( 53 os.path.expanduser("~/nightly_test_reports"), 54 "%s.%s" % (timestamp, board), 55 ) 56 57 def _ParseVanillaImage(self, trybot_image): 58 """ 59 Parse a trybot artifact name to get corresponding vanilla image. 60 61 This function takes an artifact name, such as 62 'trybot-daisy-release/R40-6394.0.0-b1389', and returns the 63 corresponding official build name, e.g. 'daisy-release/R40-6394.0.0'. 64 """ 65 start_pos = trybot_image.find(self._build) 66 end_pos = trybot_image.rfind("-b") 67 vanilla_image = trybot_image[start_pos:end_pos] 68 return vanilla_image 69 70 def _FinishSetup(self): 71 """ 72 Make sure testing_rsa file is properly set up. 73 """ 74 # Fix protections on ssh key 75 command = ("chmod 600 /var/cache/chromeos-cache/distfiles/target" 76 "/chrome-src-internal/src/third_party/chromite/ssh_keys" 77 "/testing_rsa") 78 ret_val = self._ce.ChrootRunCommand(self._chromeos_root, command) 79 if ret_val != 0: 80 raise RuntimeError("chmod for testing_rsa failed") 81 82 def _TestImages(self, trybot_image, vanilla_image): 83 """ 84 Create crosperf experiment file. 85 86 Given the names of the trybot and vanilla images, create the 87 appropriate crosperf experiment file and launch crosperf on it. 88 """ 89 experiment_file_dir = os.path.join (self._chromeos_root, "..", 90 self._weekday) 91 experiment_file_name = "%s_toolchain_experiment.txt" % self._board 92 experiment_file = os.path.join (experiment_file_dir, 93 experiment_file_name) 94 experiment_header = """ 95 board: %s 96 remote: %s 97 retries: 1 98 """ % (self._board, self._remotes) 99 experiment_tests = """ 100 benchmark: all_toolchain_perf { 101 suite: telemetry_Crosperf 102 iterations: 3 103 } 104 """ 105 with open(experiment_file, "w") as f: 106 print >> f, experiment_header 107 print >> f, experiment_tests 108 109 # Now add vanilla to test file. 110 official_image = """ 111 vanilla_image { 112 chromeos_root: %s 113 chrome_src: /usr/local/google/crostc/new-chrome-src 114 build: %s 115 } 116 """ % (self._chromeos_root, vanilla_image) 117 print >> f, official_image 118 119 experiment_image = """ 120 test_image { 121 chromeos_root: %s 122 chrome_src: /usr/local/google/crostc/new-chrome-src 123 build: %s 124 } 125 """ % (self._chromeos_root, trybot_image) 126 print >> f, experiment_image 127 128 crosperf = os.path.join(TOOLCHAIN_DIR, 129 "crosperf", 130 "crosperf") 131 command = ("%s --no_email=True --results_dir=%s %s" % 132 (crosperf, self._reports_dir, experiment_file)) 133 134 ret = self._ce.RunCommand(command) 135 if ret != 0: 136 raise RuntimeError("Couldn't run crosperf!") 137 return 138 139 def _CopyWeeklyReportFiles(self, trybot_image, vanilla_image): 140 """ 141 Put files in place for running seven-day reports. 142 143 Create tar files of the custom and official images and copy them 144 to the weekly reports directory, so they exist when the weekly report 145 gets generated. IMPORTANT NOTE: This function must run *after* 146 crosperf has been run; otherwise the vanilla images will not be there. 147 """ 148 149 dry_run = False 150 if (os.getlogin() != ROLE_ACCOUNT): 151 self._l.LogOutput("Running this from non-role account; not copying " 152 "tar files for weekly reports.") 153 dry_run = True 154 155 images_path = os.path.join(os.path.realpath(self._chromeos_root), 156 "chroot/tmp") 157 158 data_dir = os.path.join(WEEKLY_REPORTS_ROOT, self._board) 159 dest_dir = os.path.join (data_dir, self._weekday) 160 if not os.path.exists(dest_dir): 161 os.makedirs(dest_dir) 162 163 # Make sure dest_dir is empty (clean out last week's data). 164 cmd = "cd %s; rm -Rf %s_*_image*" % (dest_dir, self._weekday) 165 if dry_run: 166 print "CMD: %s" % cmd 167 else: 168 self._ce.RunCommand(cmd) 169 170 # Now create new tar files and copy them over. 171 labels = [ "test", "vanilla" ] 172 for label_name in labels: 173 if label_name == "test": 174 test_path = trybot_image 175 else: 176 test_path = vanilla_image 177 tar_file_name = "%s_%s_image.tar" % (self._weekday, label_name) 178 cmd = ("cd %s; tar -cvf %s %s/chromiumos_test_image.bin; " 179 "cp %s %s/.") % (images_path, 180 tar_file_name, 181 test_path, 182 tar_file_name, 183 dest_dir) 184 if dry_run: 185 print "CMD: %s" % cmd 186 tar_ret = 0 187 else: 188 tar_ret = self._ce.RunCommand(cmd) 189 if tar_ret: 190 self._l.LogOutput("Error while creating/copying test tar file(%s)." 191 % tar_file_name) 192 193 def _SendEmail(self): 194 """Find email message generated by crosperf and send it.""" 195 filename = os.path.join(self._reports_dir, 196 "msg_body.html") 197 if (os.path.exists(filename) and 198 os.path.exists(os.path.expanduser(MAIL_PROGRAM))): 199 command = ('cat %s | %s -s "buildbot test results, %s" -team -html' 200 % (filename, MAIL_PROGRAM, self._board)) 201 self._ce.RunCommand(command) 202 203 def DoAll(self): 204 """ 205 Main function inside ToolchainComparator class. 206 207 Launch trybot, get image names, create crosperf experiment file, run 208 crosperf, and copy images into seven-day report directories. 209 """ 210 date_str = datetime.date.today() 211 description = "master_%s_%s_%s" % (USE_NEXT_GCC_PATCH, 212 self._build, 213 date_str) 214 trybot_image = buildbot_utils.GetTrybotImage(self._chromeos_root, 215 self._build, 216 [ USE_NEXT_GCC_PATCH ], 217 description, 218 build_toolchain=True) 219 220 vanilla_image = self._ParseVanillaImage(trybot_image) 221 222 print ("trybot_image: %s" % trybot_image) 223 print ("vanilla_image: %s" % vanilla_image) 224 if len(trybot_image) == 0: 225 self._l.LogError("Unable to find trybot_image for %s!" % description) 226 return 1 227 if len(vanilla_image) == 0: 228 self._l.LogError("Unable to find vanilla image for %s!" % description) 229 return 1 230 if os.getlogin() == ROLE_ACCOUNT: 231 self._FinishSetup() 232 233 self._TestImages(trybot_image, vanilla_image) 234 self._SendEmail() 235 # Only try to copy the image files if the test runs ran successfully. 236 self._CopyWeeklyReportFiles(trybot_image, vanilla_image) 237 return 0 238 239 240def Main(argv): 241 """The main function.""" 242 243 # Common initializations 244 command_executer.InitCommandExecuter() 245 parser = optparse.OptionParser() 246 parser.add_option("--remote", 247 dest="remote", 248 help="Remote machines to run tests on.") 249 parser.add_option("--board", 250 dest="board", 251 default="x86-zgb", 252 help="The target board.") 253 parser.add_option("--chromeos_root", 254 dest="chromeos_root", 255 help="The chromeos root from which to run tests.") 256 parser.add_option("--weekday", default="", 257 dest="weekday", 258 help="The day of the week for which to run tests.") 259 options, _ = parser.parse_args(argv) 260 if not options.board: 261 print "Please give a board." 262 return 1 263 if not options.remote: 264 print "Please give at least one remote machine." 265 return 1 266 if not options.chromeos_root: 267 print "Please specify the ChromeOS root directory." 268 return 1 269 270 fc = ToolchainComparator(options.board, options.remote, 271 options.chromeos_root, options.weekday) 272 return fc.DoAll() 273 274 275if __name__ == "__main__": 276 retval = Main(sys.argv) 277 sys.exit(retval) 278