buildbot_test_toolchains.py revision 7f3190b3fb89522ea85b87200241962634369e9a
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 """ % (self._board, self._remotes) 98 experiment_tests = """ 99 benchmark: all_perfv2 { 100 suite: telemetry_Crosperf 101 iterations: 3 102 } 103 """ 104 with open(experiment_file, "w") as f: 105 print >> f, experiment_header 106 print >> f, experiment_tests 107 108 # Now add vanilla to test file. 109 official_image = """ 110 vanilla_image { 111 chromeos_root: %s 112 build: %s 113 } 114 """ % (self._chromeos_root, vanilla_image) 115 print >> f, official_image 116 117 experiment_image = """ 118 test_image { 119 chromeos_root: %s 120 build: %s 121 } 122 """ % (self._chromeos_root, trybot_image) 123 print >> f, experiment_image 124 125 crosperf = os.path.join(TOOLCHAIN_DIR, 126 "crosperf", 127 "crosperf") 128 command = ("%s --no_email=True --results_dir=%s %s" % (crosperf, 129 self._reports_dir, 130 experiment_file)) 131 ret = self._ce.RunCommand(command) 132 if ret != 0: 133 raise RuntimeError("Couldn't run crosperf!") 134 return 135 136 def _CopyWeeklyReportFiles(self, trybot_image, vanilla_image): 137 """ 138 Put files in place for running seven-day reports. 139 140 Create tar files of the custom and official images and copy them 141 to the weekly reports directory, so they exist when the weekly report 142 gets generated. IMPORTANT NOTE: This function must run *after* 143 crosperf has been run; otherwise the vanilla images will not be there. 144 """ 145 146 dry_run = False 147 if (os.getlogin() != ROLE_ACCOUNT): 148 self._l.LogOutput("Running this from non-role account; not copying " 149 "tar files for weekly reports.") 150 dry_run = True 151 152 images_path = os.path.join(os.path.realpath(self._chromeos_root), 153 "chroot/tmp") 154 155 data_dir = os.path.join(WEEKLY_REPORTS_ROOT, self._board) 156 dest_dir = os.path.join (data_dir, self._weekday) 157 if not os.path.exists(dest_dir): 158 os.makedirs(dest_dir) 159 160 # Make sure dest_dir is empty (clean out last week's data). 161 cmd = "cd %s; rm -Rf %s_*_image*" % (dest_dir, self._weekday) 162 if dry_run: 163 print "CMD: %s" % cmd 164 else: 165 self._ce.RunCommand(cmd) 166 167 # Now create new tar files and copy them over. 168 labels = [ "test", "vanilla" ] 169 for label_name in labels: 170 if label_name == "test": 171 test_path = trybot_image 172 else: 173 test_path = vanilla_image 174 tar_file_name = "%s_%s_image.tar" % (self._weekday, label_name) 175 cmd = ("cd %s; tar -cvf %s %s/chromiumos_test_image.bin; " 176 "cp %s %s/.") % (images_path, 177 tar_file_name, 178 test_path, 179 tar_file_name, 180 dest_dir) 181 if dry_run: 182 print "CMD: %s" % cmd 183 tar_ret = 0 184 else: 185 tar_ret = self._ce.RunCommand(cmd) 186 if tar_ret: 187 self._l.LogOutput("Error while creating/copying test tar file(%s)." 188 % tar_file_name) 189 190 def _SendEmail(self): 191 """Find email message generated by crosperf and send it.""" 192 filename = os.path.join(self._reports_dir, 193 "msg_body.html") 194 if (os.path.exists(filename) and 195 os.path.exists(os.path.expanduser(MAIL_PROGRAM))): 196 command = ('cat %s | %s -s "buildbot test results, %s" -team -html' 197 % (filename, MAIL_PROGRAM, self._board)) 198 self._ce.RunCommand(command) 199 200 def DoAll(self): 201 """ 202 Main function inside ToolchainComparator class. 203 204 Launch trybot, get image names, create crosperf experiment file, run 205 crosperf, and copy images into seven-day report directories. 206 """ 207 date_str = datetime.date.today() 208 description = "master_%s_%s_%s" % (USE_NEXT_GCC_PATCH, 209 self._build, 210 date_str) 211 trybot_image = buildbot_utils.GetTrybotImage(self._chromeos_root, 212 self._build, 213 [ USE_NEXT_GCC_PATCH ], 214 description, 215 build_toolchain=True) 216 217 vanilla_image = self._ParseVanillaImage(trybot_image) 218 219 print ("trybot_image: %s" % trybot_image) 220 print ("vanilla_image: %s" % vanilla_image) 221 if len(trybot_image) == 0: 222 self._l.LogError("Unable to find trybot_image for %s!" % description) 223 return 1 224 if len(vanilla_image) == 0: 225 self._l.LogError("Unable to find vanilla image for %s!" % description) 226 return 1 227 if os.getlogin() == ROLE_ACCOUNT: 228 self._FinishSetup() 229 230 self._TestImages(trybot_image, vanilla_image) 231 self._SendEmail() 232 # Only try to copy the image files if the test runs ran successfully. 233 self._CopyWeeklyReportFiles(trybot_image, vanilla_image) 234 return 0 235 236 237def Main(argv): 238 """The main function.""" 239 240 # Common initializations 241 command_executer.InitCommandExecuter() 242 parser = optparse.OptionParser() 243 parser.add_option("--remote", 244 dest="remote", 245 help="Remote machines to run tests on.") 246 parser.add_option("--board", 247 dest="board", 248 default="x86-zgb", 249 help="The target board.") 250 parser.add_option("--chromeos_root", 251 dest="chromeos_root", 252 help="The chromeos root from which to run tests.") 253 parser.add_option("--weekday", default="", 254 dest="weekday", 255 help="The day of the week for which to run tests.") 256 options, _ = parser.parse_args(argv) 257 if not options.board: 258 print "Please give a board." 259 return 1 260 if not options.remote: 261 print "Please give at least one remote machine." 262 return 1 263 if not options.chromeos_root: 264 print "Please specify the ChromeOS root directory." 265 return 1 266 267 fc = ToolchainComparator(options.board, options.remote, 268 options.chromeos_root, options.weekday) 269 return fc.DoAll() 270 271 272if __name__ == "__main__": 273 retval = Main(sys.argv) 274 sys.exit(retval) 275