vanilla_vs_fdo.py revision f81680c018729fd4499e1e200d04b48c4b90127c
1#!/usr/bin/python2.6 2# 3# Copyright 2011 Google Inc. All Rights Reserved. 4 5"""Script to build chrome with FDO and compare performance against no FDO.""" 6 7import getpass 8import optparse 9import os 10import sys 11 12import image_chromeos 13import setup_chromeos 14from utils import command_executer 15from utils import misc 16from utils import logger 17 18 19class Patcher(object): 20 def __init__(self, dir_to_patch, patch_file): 21 self._dir_to_patch = dir_to_patch 22 self._patch_file = patch_file 23 self._base_patch_command = "patch -p0 %%s < %s" % patch_file 24 self._ce = command_executer.GetCommandExecuter() 25 26 def _RunPatchCommand(self, args): 27 patch_command = self._base_patch_command % args 28 command = ("cd %s && %s" % (self._dir_to_patch, 29 patch_command)) 30 return self._ce.RunCommand(command) 31 32 def _ApplyPatch(self, args): 33 full_args = "%s --dry-run" % args 34 ret = self._RunPatchCommand(full_args) 35 if ret: 36 raise Exception("Patch dry run failed!") 37 ret = self._RunPatchCommand(args) 38 if ret: 39 raise Exception("Patch application failed!") 40 41 def __enter__(self): 42 self._ApplyPatch("") 43 44 def __exit__(self, type, value, traceback): 45 self._ApplyPatch("-R") 46 47 48class FDOComparator(object): 49 def __init__(self, board, remotes, ebuild_version, plus_pgo, minus_pgo, 50 update_pgo, chromeos_root): 51 self._board = board 52 self._remotes = remotes 53 self._ebuild_version = ebuild_version 54 self._remote = remotes.split(",")[0] 55 self._chromeos_root = chromeos_root 56 self._profile_dir = "profile_dir" 57 self._profile_path = os.path.join(self._chromeos_root, 58 "src", 59 "scripts", 60 os.path.basename(self._profile_dir)) 61 self._plus_pgo = plus_pgo 62 self._minus_pgo = minus_pgo 63 self._update_pgo = update_pgo 64 65 self._ce = command_executer.GetCommandExecuter() 66 self._l = logger.GetLogger() 67 68 def _CheckoutChromeOS(self): 69 if not os.path.exists(self._chromeos_root): 70 setup_chromeos_args = [setup_chromeos.__file__, 71 "--dir=%s" % self._chromeos_root, 72 "--minilayout"] 73 setup_chromeos.Main(setup_chromeos_args) 74 75 def _BuildChromeOSUsingBinaries(self): 76 image_dir = misc.GetImageDir(self._chromeos_root, self._board) 77 command = "equery-%s l chromeos" % self._board 78 ret = self._ce.ChrootRunCommand(self._chromeos_root, command) 79 if ret: 80 command = misc.GetSetupBoardCommand(self._board, 81 usepkg=True) 82 ret = self._ce.ChrootRunCommand(self._chromeos_root, 83 command) 84 if ret: 85 raise Exception("Couldn't run setup_board!") 86 command = misc.GetBuildPackagesCommand(self._board, 87 True) 88 ret = self._ce.ChrootRunCommand(self._chromeos_root, 89 command) 90 if ret: 91 raise Exception("Couldn't run build_packages!") 92 93 def _ReportMismatches(self, build_log): 94 mismatch_signature = "-Wcoverage-mismatch" 95 mismatches = build_log.count(mismatch_signature) 96 self._l.LogOutput("Total mismatches: %s" % mismatches) 97 stale_files = set([]) 98 for line in build_log.splitlines(): 99 if mismatch_signature in line: 100 filename = line.split(":")[0] 101 stale_files.add(filename) 102 self._l.LogOutput("Total stale files: %s" % len(stale_files)) 103 104 def _BuildChromeAndImage(self, ebuild_version="", env_dict={}, cflags="", 105 cxxflags="", ldflags="", label="", 106 build_image_args=""): 107 env_string = misc.GetEnvStringFromDict(env_dict) 108 if not label: 109 label = " ".join([env_string, 110 cflags, 111 cxxflags, 112 ldflags, 113 ebuild_version]) 114 label = label.strip() 115 label = misc.GetFilenameFromString(label) 116 if not misc.DoesLabelExist(self._chromeos_root, self._board, label): 117 build_chrome_browser_args = ["--clean", 118 "--chromeos_root=%s" % self._chromeos_root, 119 "--board=%s" % self._board, 120 "--env=%r" % env_string, 121 "--cflags=%r" % cflags, 122 "--cxxflags=%r" % cxxflags, 123 "--ldflags=%r" % ldflags, 124 "--ebuild_version=%s" % ebuild_version, 125 "--build_image_args=%s" % build_image_args] 126 127 build_chrome_browser = os.path.join(os.path.dirname(__file__), 128 "..", 129 "build_chrome_browser.py") 130 command = "python %s %s" % (build_chrome_browser, 131 " ".join(build_chrome_browser_args)) 132 ret, out, err = self._ce.RunCommand(command, 133 return_output=True) 134 if "-fprofile-use" in cxxflags: 135 self._ReportMismatches(out) 136 137 if ret: 138 raise Exception("Couldn't build chrome browser!") 139 misc.LabelLatestImage(self._chromeos_root, self._board, label) 140 return label 141 142 def _TestLabels(self, labels): 143 experiment_file = "pgo_experiment.txt" 144 experiment_header = """ 145 board: %s 146 remote: %s 147 """ % (self._board, self._remotes) 148 experiment_tests = """ 149 benchmark: desktopui_PyAutoPerfTests { 150 iterations: 1 151 } 152 """ 153 with open(experiment_file, "w") as f: 154 print >>f, experiment_header 155 print >>f, experiment_tests 156 for label in labels: 157 # TODO(asharif): Fix crosperf so it accepts labels with symbols 158 crosperf_label = label 159 crosperf_label = crosperf_label.replace("-", "minus") 160 crosperf_label = crosperf_label.replace("+", "plus") 161 experiment_image = """ 162 %s { 163 chromeos_image: %s 164 } 165 """ % (crosperf_label, 166 os.path.join(misc.GetImageDir(self._chromeos_root, self._board), 167 label, 168 "chromiumos_test_image.bin")) 169 print >>f, experiment_image 170 crosperf = os.path.join(os.path.dirname(__file__), 171 "..", 172 "crosperf", 173 "crosperf") 174 command = "%s %s" % (crosperf, experiment_file) 175 ret = self._ce.RunCommand(command) 176 if ret: 177 raise Exception("Couldn't run crosperf!") 178 179 def _ImageRemote(self, label): 180 image_path = os.path.join(misc.GetImageDir(self._chromeos_root, 181 self._board), 182 label, 183 "chromiumos_test_image.bin") 184 image_chromeos_args = [image_chromeos.__file__, 185 "--chromeos_root=%s" % self._chromeos_root, 186 "--image=%s" % image_path, 187 "--remote=%s" % self._remote, 188 "--board=%s" % self._board] 189 image_chromeos.Main(image_chromeos_args) 190 191 def _ProfileRemote(self): 192 profile_cycler = os.path.join(os.path.dirname(__file__), 193 "profile_cycler.py") 194 profile_cycler_args = ["--chromeos_root=%s" % self._chromeos_root, 195 "--cycler=all", 196 "--board=%s" % self._board, 197 "--profile_dir=%s" % self._profile_path, 198 "--remote=%s" % self._remote] 199 command = "python %s %s" % (profile_cycler, " ".join(profile_cycler_args)) 200 ret = self._ce.RunCommand(command) 201 if ret: 202 raise Exception("Couldn't profile cycler!") 203 204 def _BuildGenerateImage(self): 205 # TODO(asharif): add cflags as well. 206 labels_list = ["fprofile-generate", self._ebuild_version] 207 label = "_".join(labels_list) 208 generate_label = self._BuildChromeAndImage( 209 env_dict={"USE": "chrome_internal -pgo pgo_generate"}, 210 label=label, 211 ebuild_version=self._ebuild_version, 212 build_image_args="--rootfs_boost_size=400") 213 return generate_label 214 215 def _BuildUseImage(self): 216 ctarget = misc.GetCtargetFromBoard(self._board, self._chromeos_root) 217 chroot_profile_dir = os.path.join("/home/%s/trunk" % getpass.getuser(), 218 "src", 219 "scripts", 220 self._profile_dir, 221 ctarget) 222 cflags = ("-fprofile-use " 223 "-fprofile-correction " 224 "-Wno-error " 225 "-fdump-tree-optimized-blocks-lineno " 226 "-fdump-ipa-profile-blocks-lineno " 227 "-fno-vpt " 228 "-fprofile-dir=%s" % 229 chroot_profile_dir) 230 labels_list = ["updated_pgo", self._ebuild_version] 231 label = "_".join(labels_list) 232 pgo_use_label = self._BuildChromeAndImage( 233 env_dict={"USE": "chrome_internal -pgo"}, 234 cflags=cflags, 235 cxxflags=cflags, 236 ldflags=cflags, 237 label=label, 238 ebuild_version=self._ebuild_version) 239 return pgo_use_label 240 241 def DoAll(self): 242 self._CheckoutChromeOS() 243 self._BuildChromeOSUsingBinaries() 244 labels = [] 245 246 if self._minus_pgo: 247 minus_pgo = self._BuildChromeAndImage(env_dict={"USE": "chrome_internal -pgo"}, 248 ebuild_version=self._ebuild_version) 249 labels.append(minus_pgo) 250 if self._plus_pgo: 251 plus_pgo = self._BuildChromeAndImage(env_dict={"USE": "chrome_internal pgo"}, 252 ebuild_version=self._ebuild_version) 253 labels.append(plus_pgo) 254 255 if self._update_pgo: 256 if not os.path.exists(self._profile_path): 257 # Build Chrome with -fprofile-generate 258 generate_label = self._BuildGenerateImage() 259 # Image to the remote box. 260 self._ImageRemote(generate_label) 261 # Profile it using all page cyclers. 262 self._ProfileRemote() 263 264 # Use the profile directory to rebuild it. 265 updated_pgo_label = self._BuildUseImage() 266 labels.append(updated_pgo_label) 267 268 # Run crosperf on all images now. 269 self._TestLabels(labels) 270 return 0 271 272 273def Main(argv): 274 """The main function.""" 275 # Common initializations 276### command_executer.InitCommandExecuter(True) 277 command_executer.InitCommandExecuter() 278 parser = optparse.OptionParser() 279 parser.add_option("--remote", 280 dest="remote", 281 help="Remote machines to run tests on.") 282 parser.add_option("--board", 283 dest="board", 284 default="x86-zgb", 285 help="The target board.") 286 parser.add_option("--ebuild_version", 287 dest="ebuild_version", 288 default="", 289 help="The Chrome ebuild version to use.") 290 parser.add_option("--plus_pgo", 291 dest="plus_pgo", 292 action="store_true", 293 default=False, 294 help="Build USE=+pgo.") 295 parser.add_option("--minus_pgo", 296 dest="minus_pgo", 297 action="store_true", 298 default=False, 299 help="Build USE=-pgo.") 300 parser.add_option("--update_pgo", 301 dest="update_pgo", 302 action="store_true", 303 default=False, 304 help="Update pgo and build Chrome with the update.") 305 parser.add_option("--chromeos_root", 306 dest="chromeos_root", 307 default=False, 308 help="The chromeos root directory") 309 options, _ = parser.parse_args(argv) 310 if not options.board: 311 print "Please give a board." 312 return 1 313 if not options.remote: 314 print "Please give at least one remote machine." 315 return 1 316 if not options.chromeos_root: 317 print "Please provide the chromeos root directory." 318 return 1 319 if not any((options.minus_pgo, options.plus_pgo, options.update_pgo)): 320 print "Please provide at least one build option." 321 return 1 322 fc = FDOComparator(options.board, 323 options.remote, 324 options.ebuild_version, 325 options.plus_pgo, 326 options.minus_pgo, 327 options.update_pgo, 328 os.path.expanduser(options.chromeos_root)) 329 return fc.DoAll() 330 331 332if __name__ == "__main__": 333 retval = Main(sys.argv) 334 sys.exit(retval) 335