Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2013 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 """Run Performance Test Bisect Tool | 6 """Run Performance Test Bisect Tool |
| 7 | 7 |
| 8 This script is used by a trybot to run the src/tools/bisect-perf-regression.py | 8 This script is used by a trybot to run the src/tools/bisect-perf-regression.py |
| 9 script with the parameters specified in run-bisect-perf-regression.cfg. It will | 9 script with the parameters specified in run-bisect-perf-regression.cfg. It will |
| 10 check out a copy of the depot in a subdirectory 'bisect' of the working | 10 check out a copy of the depot in a subdirectory 'bisect' of the working |
| 11 directory provided, and run the bisect-perf-regression.py script there. | 11 directory provided, and run the bisect-perf-regression.py script there. |
| 12 | |
| 13 """ | 12 """ |
| 14 | 13 |
| 15 import imp | |
| 16 import optparse | 14 import optparse |
| 17 import os | 15 import os |
| 18 import platform | 16 import platform |
| 19 import subprocess | 17 import subprocess |
| 20 import sys | 18 import sys |
| 21 import traceback | 19 import traceback |
| 22 | 20 |
| 23 from auto_bisect import bisect_utils | 21 from auto_bisect import bisect_utils |
| 24 | 22 |
| 25 bisect = imp.load_source('bisect-perf-regression', | 23 # Special import required because of dashes in file name. |
| 26 os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])), | 24 bisect = __import__('bisect-perf-regression') |
|
qyearsley
2014/07/24 21:36:37
Even if run-bisect-perf-regression.py is run from
| |
| 27 'bisect-perf-regression.py')) | |
| 28 | |
| 29 | 25 |
| 30 CROS_BOARD_ENV = 'BISECT_CROS_BOARD' | 26 CROS_BOARD_ENV = 'BISECT_CROS_BOARD' |
| 31 CROS_IP_ENV = 'BISECT_CROS_IP' | 27 CROS_IP_ENV = 'BISECT_CROS_IP' |
| 32 | 28 |
| 29 # Default config file names. | |
| 30 BISECT_REGRESSION_CONFIG = 'run-bisect-perf-regression.cfg' | |
| 31 RUN_TEST_CONFIG = 'run-perf-test.cfg' | |
| 32 WEBKIT_RUN_TEST_CONFIG = os.path.join( | |
| 33 '..', 'third_party', 'WebKit', 'Tools', 'run-perf-test.cfg') | |
| 33 | 34 |
| 34 class Goma(object): | 35 class Goma(object): |
| 36 """Convenience class to start and stop goma.""" | |
| 35 | 37 |
| 36 def __init__(self, path_to_goma): | 38 def __init__(self, path_to_goma): |
| 37 self._abs_path_to_goma = None | 39 self._abs_path_to_goma = None |
| 38 self._abs_path_to_goma_file = None | 40 self._abs_path_to_goma_file = None |
| 39 if path_to_goma: | 41 if not path_to_goma: |
| 40 self._abs_path_to_goma = os.path.abspath(path_to_goma) | 42 return |
| 41 self._abs_path_to_goma_file = self._GetExecutablePath( | 43 self._abs_path_to_goma = os.path.abspath(path_to_goma) |
| 42 self._abs_path_to_goma) | 44 filename = 'goma_ctl.bat' if os.name == 'nt' else 'goma_ctl.sh' |
|
qyearsley
2014/07/24 21:36:37
I thought this is simpler than how it was done wit
| |
| 45 self._abs_path_to_goma_file = os.path.join(self._abs_path_to_goma, filename) | |
| 43 | 46 |
| 44 def __enter__(self): | 47 def __enter__(self): |
| 45 if self._HasGOMAPath(): | 48 if self._HasGomaPath(): |
|
qyearsley
2014/07/24 21:36:37
Goma is not spelled with all caps in its official
| |
| 46 self._SetupAndStart() | 49 self._SetupAndStart() |
| 47 return self | 50 return self |
| 48 | 51 |
| 49 def __exit__(self, *_): | 52 def __exit__(self, *_): |
| 50 if self._HasGOMAPath(): | 53 if self._HasGomaPath(): |
| 51 self._Stop() | 54 self._Stop() |
| 52 | 55 |
| 53 def _HasGOMAPath(self): | 56 def _HasGomaPath(self): |
| 54 return bool(self._abs_path_to_goma) | 57 return bool(self._abs_path_to_goma) |
| 55 | 58 |
| 56 def _GetExecutablePath(self, path_to_goma): | |
| 57 if os.name == 'nt': | |
| 58 return os.path.join(path_to_goma, 'goma_ctl.bat') | |
| 59 else: | |
| 60 return os.path.join(path_to_goma, 'goma_ctl.sh') | |
| 61 | |
| 62 def _SetupEnvVars(self): | 59 def _SetupEnvVars(self): |
| 63 if os.name == 'nt': | 60 if os.name == 'nt': |
| 64 os.environ['CC'] = (os.path.join(self._abs_path_to_goma, 'gomacc.exe') + | 61 os.environ['CC'] = (os.path.join(self._abs_path_to_goma, 'gomacc.exe') + |
| 65 ' cl.exe') | 62 ' cl.exe') |
| 66 os.environ['CXX'] = (os.path.join(self._abs_path_to_goma, 'gomacc.exe') + | 63 os.environ['CXX'] = (os.path.join(self._abs_path_to_goma, 'gomacc.exe') + |
| 67 ' cl.exe') | 64 ' cl.exe') |
| 68 else: | 65 else: |
| 69 os.environ['PATH'] = os.pathsep.join([self._abs_path_to_goma, | 66 os.environ['PATH'] = os.pathsep.join([self._abs_path_to_goma, |
| 70 os.environ['PATH']]) | 67 os.environ['PATH']]) |
| 71 | 68 |
| 72 def _SetupAndStart(self): | 69 def _SetupAndStart(self): |
| 73 """Sets up GOMA and launches it. | 70 """Sets up goma and launches it. |
| 74 | 71 |
| 75 Args: | 72 Args: |
| 76 path_to_goma: Path to goma directory. | 73 path_to_goma: Path to goma directory. |
| 77 | 74 |
| 78 Returns: | 75 Returns: |
| 79 True if successful.""" | 76 True if successful.""" |
| 80 self._SetupEnvVars() | 77 self._SetupEnvVars() |
| 81 | 78 |
| 82 # Sometimes goma is lingering around if something went bad on a previous | 79 # Sometimes goma is lingering around if something went bad on a previous |
| 83 # run. Stop it before starting a new process. Can ignore the return code | 80 # run. Stop it before starting a new process. Can ignore the return code |
| 84 # since it will return an error if it wasn't running. | 81 # since it will return an error if it wasn't running. |
| 85 self._Stop() | 82 self._Stop() |
| 86 | 83 |
| 87 if subprocess.call([self._abs_path_to_goma_file, 'start']): | 84 if subprocess.call([self._abs_path_to_goma_file, 'start']): |
| 88 raise RuntimeError('GOMA failed to start.') | 85 raise RuntimeError('Goma failed to start.') |
| 89 | 86 |
| 90 def _Stop(self): | 87 def _Stop(self): |
| 91 subprocess.call([self._abs_path_to_goma_file, 'stop']) | 88 subprocess.call([self._abs_path_to_goma_file, 'stop']) |
| 92 | 89 |
| 93 | 90 |
| 91 def _LoadConfigFile(config_file_path): | |
| 92 """Loads to given file as a python module and returns the config dictionary. | |
| 94 | 93 |
| 95 def _LoadConfigFile(path_to_file): | 94 The config file is loaded as a Python module. |
| 96 """Attempts to load the specified config file as a module | |
| 97 and grab the global config dict. | |
| 98 | 95 |
| 99 Args: | 96 Args: |
| 100 path_to_file: Path to the file. | 97 config_file_path: Path to the config file. |
| 101 | 98 |
| 102 Returns: | 99 Returns: |
| 103 The config dict which should be formatted as follows: | 100 If successful, returns the config dict loaded from the file. If no |
| 104 {'command': string, 'good_revision': string, 'bad_revision': string | 101 such dictionary could be loaded, returns the empty dictionary. |
| 105 'metric': string, etc...}. | |
| 106 Returns None on failure. | |
| 107 """ | 102 """ |
| 108 try: | 103 try: |
| 109 local_vars = {} | 104 local_vars = {} |
| 110 execfile(path_to_file, local_vars) | 105 execfile(config_file_path, local_vars) |
| 111 | |
| 112 return local_vars['config'] | 106 return local_vars['config'] |
| 113 except: | 107 except Exception: |
| 114 print | 108 print |
| 115 traceback.print_exc() | 109 traceback.print_exc() |
| 116 print | 110 print |
| 117 return {} | 111 return {} |
| 118 | 112 |
| 119 | 113 |
| 120 def _ValidateConfigFile(config_contents, valid_parameters): | 114 def _ValidateConfigFile(config_contents, valid_parameters): |
| 121 """Validates the config file contents, checking whether all values are | 115 """Validates the config file contents, checking whether all values are |
| 122 non-empty. | 116 non-empty. |
| 123 | 117 |
| 124 Args: | 118 Args: |
| 125 config_contents: Contents of the config file passed from _LoadConfigFile. | 119 config_contents: A config dictionary. |
| 126 valid_parameters: A list of parameters to check for. | 120 valid_parameters: A list of parameters to check for. |
| 127 | 121 |
| 128 Returns: | 122 Returns: |
| 129 True if valid. | 123 True if valid. |
| 130 """ | 124 """ |
| 131 try: | 125 for parameter in valid_parameters: |
| 132 [config_contents[current_parameter] | 126 if parameter not in config_contents: |
| 133 for current_parameter in valid_parameters] | 127 return False |
| 134 config_has_values = [v and type(v) is str | 128 value = config_contents[parameter] |
| 135 for v in config_contents.values() if v] | 129 if not value or type(value) is not str: |
| 136 return config_has_values | 130 return False |
| 137 except KeyError: | 131 return True |
|
qyearsley
2014/07/24 21:36:37
I believe that this is equivalent.
PTAL to verify
| |
| 138 return False | |
| 139 | 132 |
| 140 | 133 |
| 141 def _ValidatePerfConfigFile(config_contents): | 134 def _ValidatePerfConfigFile(config_contents): |
| 142 """Validates that the perf config file contents. This is used when we're | 135 """Validates the perf config file contents. |
| 143 doing a perf try job, rather than a bisect. The file is called | 136 |
| 144 run-perf-test.cfg by default. | 137 This is used when we're doing a perf try job, rather than a bisect. |
| 138 The config file is called run-perf-test.cfg by default. | |
| 145 | 139 |
| 146 The parameters checked are the required parameters; any additional optional | 140 The parameters checked are the required parameters; any additional optional |
| 147 parameters won't be checked and validation will still pass. | 141 parameters won't be checked and validation will still pass. |
| 148 | 142 |
| 149 Args: | 143 Args: |
| 150 config_contents: Contents of the config file passed from _LoadConfigFile. | 144 config_contents: A config dictionary. |
| 151 | 145 |
| 152 Returns: | 146 Returns: |
| 153 True if valid. | 147 True if valid. |
| 154 """ | 148 """ |
| 155 valid_parameters = ['command', 'metric', 'repeat_count', 'truncate_percent', | 149 valid_parameters = [ |
| 156 'max_time_minutes'] | 150 'command', |
| 151 'metric', | |
| 152 'repeat_count', | |
| 153 'truncate_percent', | |
| 154 'max_time_minutes', | |
| 155 ] | |
| 157 return _ValidateConfigFile(config_contents, valid_parameters) | 156 return _ValidateConfigFile(config_contents, valid_parameters) |
| 158 | 157 |
| 159 | 158 |
| 160 def _ValidateBisectConfigFile(config_contents): | 159 def _ValidateBisectConfigFile(config_contents): |
| 161 """Validates that the bisect config file contents. The parameters checked are | 160 """Validates the bisect config file contents. |
| 162 the required parameters; any additional optional parameters won't be checked | 161 |
| 163 and validation will still pass. | 162 The parameters checked are the required parameters; any additional optional |
| 163 parameters won't be checked and validation will still pass. | |
| 164 | 164 |
| 165 Args: | 165 Args: |
| 166 config_contents: Contents of the config file passed from _LoadConfigFile. | 166 config_contents: A config dictionary. |
| 167 | 167 |
| 168 Returns: | 168 Returns: |
| 169 True if valid. | 169 True if valid. |
| 170 """ | 170 """ |
| 171 valid_params = ['command', 'good_revision', 'bad_revision', 'metric', | 171 valid_params = [ |
| 172 'repeat_count', 'truncate_percent', 'max_time_minutes'] | 172 'command', |
| 173 'good_revision', | |
| 174 'bad_revision', | |
| 175 'metric', | |
| 176 'repeat_count', | |
| 177 'truncate_percent', | |
| 178 'max_time_minutes', | |
| 179 ] | |
| 173 return _ValidateConfigFile(config_contents, valid_params) | 180 return _ValidateConfigFile(config_contents, valid_params) |
| 174 | 181 |
| 175 | 182 |
| 176 def _OutputFailedResults(text_to_print): | 183 def _OutputFailedResults(text_to_print): |
| 177 bisect_utils.OutputAnnotationStepStart('Results - Failed') | 184 bisect_utils.OutputAnnotationStepStart('Results - Failed') |
| 178 print | 185 print |
| 179 print text_to_print | 186 print text_to_print |
| 180 print | 187 print |
| 181 bisect_utils.OutputAnnotationStepClosed() | 188 bisect_utils.OutputAnnotationStepClosed() |
| 182 | 189 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 218 opts_dict['target_platform'] = 'android' | 225 opts_dict['target_platform'] = 'android' |
| 219 elif 'android-chrome' in config['command']: | 226 elif 'android-chrome' in config['command']: |
| 220 opts_dict['target_platform'] = 'android-chrome' | 227 opts_dict['target_platform'] = 'android-chrome' |
| 221 else: | 228 else: |
| 222 opts_dict['target_platform'] = 'android' | 229 opts_dict['target_platform'] = 'android' |
| 223 | 230 |
| 224 return bisect.BisectOptions.FromDict(opts_dict) | 231 return bisect.BisectOptions.FromDict(opts_dict) |
| 225 | 232 |
| 226 | 233 |
| 227 def _RunPerformanceTest(config, path_to_file): | 234 def _RunPerformanceTest(config, path_to_file): |
| 228 # Bisect script expects to be run from src | 235 """Runs a performance test with and without the current patch. |
| 236 | |
| 237 Args: | |
| 238 config: Contents of the config file, a dictionary. | |
| 239 path_to_file: Path to the bisect-perf-regression.py script. | |
| 240 | |
| 241 Attempts to build and run the current revision with and without the | |
| 242 current patch, with the parameters passed in. | |
| 243 """ | |
| 244 # Bisect script expects to be run from the src directory | |
| 229 os.chdir(os.path.join(path_to_file, '..')) | 245 os.chdir(os.path.join(path_to_file, '..')) |
| 230 | 246 |
| 231 bisect_utils.OutputAnnotationStepStart('Building With Patch') | 247 bisect_utils.OutputAnnotationStepStart('Building With Patch') |
| 232 | 248 |
| 233 opts = _CreateBisectOptionsFromConfig(config) | 249 opts = _CreateBisectOptionsFromConfig(config) |
| 234 b = bisect.BisectPerformanceMetrics(None, opts) | 250 b = bisect.BisectPerformanceMetrics(None, opts) |
| 235 | 251 |
| 236 if bisect_utils.RunGClient(['runhooks']): | 252 if bisect_utils.RunGClient(['runhooks']): |
| 237 raise RuntimeError('Failed to run gclient runhooks') | 253 raise RuntimeError('Failed to run gclient runhooks') |
| 238 | 254 |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 312 def _SetupAndRunPerformanceTest(config, path_to_file, path_to_goma): | 328 def _SetupAndRunPerformanceTest(config, path_to_file, path_to_goma): |
| 313 """Attempts to build and run the current revision with and without the | 329 """Attempts to build and run the current revision with and without the |
| 314 current patch, with the parameters passed in. | 330 current patch, with the parameters passed in. |
| 315 | 331 |
| 316 Args: | 332 Args: |
| 317 config: The config read from run-perf-test.cfg. | 333 config: The config read from run-perf-test.cfg. |
| 318 path_to_file: Path to the bisect-perf-regression.py script. | 334 path_to_file: Path to the bisect-perf-regression.py script. |
| 319 path_to_goma: Path to goma directory. | 335 path_to_goma: Path to goma directory. |
| 320 | 336 |
| 321 Returns: | 337 Returns: |
| 322 0 on success, otherwise 1. | 338 The exit code of bisect-perf-regression.py: 0 on success, otherwise 1. |
| 323 """ | 339 """ |
| 324 try: | 340 try: |
| 325 with Goma(path_to_goma) as goma: | 341 with Goma(path_to_goma) as _: |
| 326 config['use_goma'] = bool(path_to_goma) | 342 config['use_goma'] = bool(path_to_goma) |
| 327 config['goma_dir'] = os.path.abspath(path_to_goma) | 343 config['goma_dir'] = os.path.abspath(path_to_goma) |
| 328 _RunPerformanceTest(config, path_to_file) | 344 _RunPerformanceTest(config, path_to_file) |
| 329 return 0 | 345 return 0 |
| 330 except RuntimeError, e: | 346 except RuntimeError, e: |
| 331 bisect_utils.OutputAnnotationStepClosed() | 347 bisect_utils.OutputAnnotationStepClosed() |
| 332 _OutputFailedResults('Error: %s' % e.message) | 348 _OutputFailedResults('Error: %s' % e.message) |
| 333 return 1 | 349 return 1 |
| 334 | 350 |
| 335 | 351 |
| 336 def _RunBisectionScript(config, working_directory, path_to_file, path_to_goma, | 352 def _RunBisectionScript( |
| 337 path_to_extra_src, dry_run): | 353 config, working_directory, path_to_file, path_to_goma, path_to_extra_src, |
| 338 """Attempts to execute src/tools/bisect-perf-regression.py with the parameters | 354 dry_run): |
| 339 passed in. | 355 """Attempts to execute bisect-perf-regression.py with the given parameters. |
| 356 | |
| 357 This function also | |
|
prasadv
2014/07/25 00:00:42
causes sheriffs to scream at us:)
?
qyearsley
2014/07/25 00:22:28
Yeah, that's an unintended side-effect of this fun
| |
| 340 | 358 |
| 341 Args: | 359 Args: |
| 342 config: A dict containing the parameters to pass to the script. | 360 config: A dict containing the parameters to pass to the script. |
| 343 working_directory: A working directory to provide to the | 361 working_directory: A working directory to provide to the |
| 344 bisect-perf-regression.py script, where it will store it's own copy of | 362 bisect-perf-regression.py script, where it will store it's own copy of |
| 345 the depot. | 363 the depot. |
| 346 path_to_file: Path to the bisect-perf-regression.py script. | 364 path_to_file: Path to the bisect-perf-regression.py script. |
| 347 path_to_goma: Path to goma directory. | 365 path_to_goma: Path to goma directory. |
| 348 path_to_extra_src: Path to extra source file. | 366 path_to_extra_src: Path to extra source file. |
| 349 dry_run: Do a dry run, skipping sync, build, and performance testing steps. | 367 dry_run: Do a dry run, skipping sync, build, and performance testing steps. |
| 350 | 368 |
| 351 Returns: | 369 Returns: |
| 352 0 on success, otherwise 1. | 370 An exit status code: 0 on success, otherwise 1. |
| 353 """ | 371 """ |
| 354 bisect_utils.OutputAnnotationStepStart('Config') | 372 bisect_utils.OutputAnnotationStepStart('Config') |
| 355 print | 373 print |
| 356 for k, v in config.iteritems(): | 374 for k, v in config.iteritems(): |
| 357 print ' %s : %s' % (k, v) | 375 print ' %s : %s' % (k, v) |
| 358 print | 376 print |
| 359 bisect_utils.OutputAnnotationStepClosed() | 377 bisect_utils.OutputAnnotationStepClosed() |
| 360 | 378 |
| 361 cmd = ['python', os.path.join(path_to_file, 'bisect-perf-regression.py'), | 379 cmd = ['python', os.path.join(path_to_file, 'bisect-perf-regression.py'), |
| 362 '-c', config['command'], | 380 '-c', config['command'], |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 380 | 398 |
| 381 cmd.extend(['--build_preference', 'ninja']) | 399 cmd.extend(['--build_preference', 'ninja']) |
| 382 | 400 |
| 383 if '--browser=cros' in config['command']: | 401 if '--browser=cros' in config['command']: |
| 384 cmd.extend(['--target_platform', 'cros']) | 402 cmd.extend(['--target_platform', 'cros']) |
| 385 | 403 |
| 386 if os.environ[CROS_BOARD_ENV] and os.environ[CROS_IP_ENV]: | 404 if os.environ[CROS_BOARD_ENV] and os.environ[CROS_IP_ENV]: |
| 387 cmd.extend(['--cros_board', os.environ[CROS_BOARD_ENV]]) | 405 cmd.extend(['--cros_board', os.environ[CROS_BOARD_ENV]]) |
| 388 cmd.extend(['--cros_remote_ip', os.environ[CROS_IP_ENV]]) | 406 cmd.extend(['--cros_remote_ip', os.environ[CROS_IP_ENV]]) |
| 389 else: | 407 else: |
| 390 print 'Error: Cros build selected, but BISECT_CROS_IP or'\ | 408 print ('Error: Cros build selected, but BISECT_CROS_IP or' |
| 391 'BISECT_CROS_BOARD undefined.' | 409 'BISECT_CROS_BOARD undefined.\n') |
| 392 print | |
| 393 return 1 | 410 return 1 |
| 394 | 411 |
| 395 if 'android' in config['command']: | 412 if 'android' in config['command']: |
| 396 if 'android-chrome-shell' in config['command']: | 413 if 'android-chrome-shell' in config['command']: |
| 397 cmd.extend(['--target_platform', 'android']) | 414 cmd.extend(['--target_platform', 'android']) |
| 398 elif 'android-chrome' in config['command']: | 415 elif 'android-chrome' in config['command']: |
| 399 cmd.extend(['--target_platform', 'android-chrome']) | 416 cmd.extend(['--target_platform', 'android-chrome']) |
| 400 else: | 417 else: |
| 401 cmd.extend(['--target_platform', 'android']) | 418 cmd.extend(['--target_platform', 'android']) |
| 402 | 419 |
| 403 if path_to_goma: | 420 if path_to_goma: |
| 404 # crbug.com/330900. For Windows XP platforms, GOMA service is not supported. | 421 # For Windows XP platforms, goma service is not supported. |
| 405 # Moreover we don't compile chrome when gs_bucket flag is set instead | 422 # Moreover we don't compile chrome when gs_bucket flag is set instead |
| 406 # use builds archives, therefore ignore GOMA service for Windows XP. | 423 # use builds archives, therefore ignore goma service for Windows XP. |
| 424 # See http://crbug.com/330900. | |
| 407 if config.get('gs_bucket') and platform.release() == 'XP': | 425 if config.get('gs_bucket') and platform.release() == 'XP': |
| 408 print ('Goma doesn\'t have a win32 binary, therefore it is not supported ' | 426 print ('Goma doesn\'t have a win32 binary, therefore it is not supported ' |
| 409 'on Windows XP platform. Please refer to crbug.com/330900.') | 427 'on Windows XP platform. Please refer to crbug.com/330900.') |
| 410 path_to_goma = None | 428 path_to_goma = None |
| 411 cmd.append('--use_goma') | 429 cmd.append('--use_goma') |
| 412 | 430 |
| 413 if path_to_extra_src: | 431 if path_to_extra_src: |
| 414 cmd.extend(['--extra_src', path_to_extra_src]) | 432 cmd.extend(['--extra_src', path_to_extra_src]) |
| 415 | 433 |
| 416 # These flags are used to download build archives from cloud storage if | 434 # These flags are used to download build archives from cloud storage if |
| 417 # available, otherwise will post a try_job_http request to build it on | 435 # available, otherwise will post a try_job_http request to build it on |
| 418 # tryserver. | 436 # tryserver. |
| 419 if config.get('gs_bucket'): | 437 if config.get('gs_bucket'): |
| 420 if config.get('builder_host') and config.get('builder_port'): | 438 if config.get('builder_host') and config.get('builder_port'): |
| 421 cmd.extend(['--gs_bucket', config['gs_bucket'], | 439 cmd.extend(['--gs_bucket', config['gs_bucket'], |
| 422 '--builder_host', config['builder_host'], | 440 '--builder_host', config['builder_host'], |
| 423 '--builder_port', config['builder_port'] | 441 '--builder_port', config['builder_port'] |
| 424 ]) | 442 ]) |
| 425 else: | 443 else: |
| 426 print ('Error: Specified gs_bucket, but missing builder_host or ' | 444 print ('Error: Specified gs_bucket, but missing builder_host or ' |
| 427 'builder_port information in config.') | 445 'builder_port information in config.') |
| 428 return 1 | 446 return 1 |
| 429 | 447 |
| 430 if dry_run: | 448 if dry_run: |
| 431 cmd.extend(['--debug_ignore_build', '--debug_ignore_sync', | 449 cmd.extend(['--debug_ignore_build', '--debug_ignore_sync', |
| 432 '--debug_ignore_perf_test']) | 450 '--debug_ignore_perf_test']) |
| 433 cmd = [str(c) for c in cmd] | 451 cmd = [str(c) for c in cmd] |
| 434 | 452 |
| 435 with Goma(path_to_goma) as goma: | 453 with Goma(path_to_goma) as _: |
| 436 return_code = subprocess.call(cmd) | 454 return_code = subprocess.call(cmd) |
| 437 | 455 |
| 438 if return_code: | 456 if return_code: |
| 439 print 'Error: bisect-perf-regression.py returned with error %d' %\ | 457 print ('Error: bisect-perf-regression.py returned with error %d\n' |
| 440 return_code | 458 % return_code) |
| 441 print | |
| 442 | 459 |
| 443 return return_code | 460 return return_code |
| 444 | 461 |
| 445 | 462 |
| 446 def main(): | 463 def _OptionParser(): |
| 447 | 464 """Returns the options parser for run-bisect-perf-regression.py.""" |
| 448 usage = ('%prog [options] [-- chromium-options]\n' | 465 usage = ('%prog [options] [-- chromium-options]\n' |
| 449 'Used by a trybot to run the bisection script using the parameters' | 466 'Used by a trybot to run the bisection script using the parameters' |
| 450 ' provided in the run-bisect-perf-regression.cfg file.') | 467 ' provided in the run-bisect-perf-regression.cfg file.') |
| 451 | |
| 452 parser = optparse.OptionParser(usage=usage) | 468 parser = optparse.OptionParser(usage=usage) |
| 453 parser.add_option('-w', '--working_directory', | 469 parser.add_option('-w', '--working_directory', |
| 454 type='str', | 470 type='str', |
| 455 help='A working directory to supply to the bisection ' | 471 help='A working directory to supply to the bisection ' |
| 456 'script, which will use it as the location to checkout ' | 472 'script, which will use it as the location to checkout ' |
| 457 'a copy of the chromium depot.') | 473 'a copy of the chromium depot.') |
| 458 parser.add_option('-p', '--path_to_goma', | 474 parser.add_option('-p', '--path_to_goma', |
| 459 type='str', | 475 type='str', |
| 460 help='Path to goma directory. If this is supplied, goma ' | 476 help='Path to goma directory. If this is supplied, goma ' |
| 461 'builds will be enabled.') | 477 'builds will be enabled.') |
| 462 parser.add_option('--path_to_config', | 478 parser.add_option('--path_to_config', |
| 463 type='str', | 479 type='str', |
| 464 help='Path to the config file to use. If this is supplied, ' | 480 help='Path to the config file to use. If this is supplied, ' |
| 465 'the bisect script will use this to override the default ' | 481 'the bisect script will use this to override the default ' |
| 466 'config file path. The script will attempt to load it ' | 482 'config file path. The script will attempt to load it ' |
| 467 'as a bisect config first, then a perf config.') | 483 'as a bisect config first, then a perf config.') |
| 468 parser.add_option('--extra_src', | 484 parser.add_option('--extra_src', |
| 469 type='str', | 485 type='str', |
| 470 help='Path to extra source file. If this is supplied, ' | 486 help='Path to extra source file. If this is supplied, ' |
| 471 'bisect script will use this to override default behavior.') | 487 'bisect script will use this to override default behavior.') |
| 472 parser.add_option('--dry_run', | 488 parser.add_option('--dry_run', |
| 473 action="store_true", | 489 action="store_true", |
| 474 help='The script will perform the full bisect, but ' | 490 help='The script will perform the full bisect, but ' |
| 475 'without syncing, building, or running the performance ' | 491 'without syncing, building, or running the performance ' |
| 476 'tests.') | 492 'tests.') |
| 477 (opts, args) = parser.parse_args() | 493 return parser |
| 478 | 494 |
| 479 path_to_current_directory = os.path.abspath(os.path.dirname(sys.argv[0])) | |
| 480 | 495 |
| 481 # If they've specified their own config file, use that instead. | 496 def main(): |
| 497 """Entry point for run-bisect-perf-regression.py. | |
| 498 | |
| 499 Reads the config file, and then tries to either bisect a regression or | |
| 500 just run a performance test, depending on the particular config parameters | |
| 501 specified in the config file. | |
| 502 """ | |
| 503 | |
| 504 parser = _OptionParser() | |
| 505 opts, _ = parser.parse_args() | |
| 506 | |
| 507 current_dir = os.path.abspath(os.path.dirname(sys.argv[0])) | |
| 508 | |
| 509 # Use the default config file path unless one was specified. | |
| 510 config_path = os.path.join(current_dir, BISECT_REGRESSION_CONFIG) | |
| 482 if opts.path_to_config: | 511 if opts.path_to_config: |
| 483 path_to_bisect_cfg = opts.path_to_config | 512 config_path = opts.path_to_config |
| 484 else: | 513 config = _LoadConfigFile(config_path) |
| 485 path_to_bisect_cfg = os.path.join(path_to_current_directory, | |
| 486 'run-bisect-perf-regression.cfg') | |
| 487 | 514 |
| 488 config = _LoadConfigFile(path_to_bisect_cfg) | 515 # Check if the config is valid for running bisect job. |
| 489 | |
| 490 # Check if the config is valid. | |
| 491 config_is_valid = _ValidateBisectConfigFile(config) | 516 config_is_valid = _ValidateBisectConfigFile(config) |
| 492 | 517 |
| 493 if config and config_is_valid: | 518 if config and config_is_valid: |
| 494 if not opts.working_directory: | 519 if not opts.working_directory: |
| 495 print 'Error: missing required parameter: --working_directory' | 520 print 'Error: missing required parameter: --working_directory\n' |
| 496 print | |
| 497 parser.print_help() | 521 parser.print_help() |
| 498 return 1 | 522 return 1 |
| 499 | 523 |
| 500 return _RunBisectionScript(config, opts.working_directory, | 524 return _RunBisectionScript( |
| 501 path_to_current_directory, opts.path_to_goma, opts.extra_src, | 525 config, opts.working_directory, current_dir, |
| 502 opts.dry_run) | 526 opts.path_to_goma, opts.extra_src, opts.dry_run) |
| 503 else: | |
| 504 perf_cfg_files = ['run-perf-test.cfg', os.path.join('..', 'third_party', | |
| 505 'WebKit', 'Tools', 'run-perf-test.cfg')] | |
| 506 | 527 |
| 507 for current_perf_cfg_file in perf_cfg_files: | 528 # If it wasn't valid for running a bisect, then maybe the user wanted |
| 508 if opts.path_to_config: | 529 # to run a perf test instead of a bisect job. Try reading any possible |
| 509 path_to_perf_cfg = opts.path_to_config | 530 # perf test config files. |
| 510 else: | 531 perf_cfg_files = [RUN_TEST_CONFIG, WEBKIT_RUN_TEST_CONFIG] |
| 511 path_to_perf_cfg = os.path.join( | 532 for current_perf_cfg_file in perf_cfg_files: |
| 512 os.path.abspath(os.path.dirname(sys.argv[0])), | 533 if opts.path_to_config: |
| 513 current_perf_cfg_file) | 534 path_to_perf_cfg = opts.path_to_config |
| 535 else: | |
| 536 path_to_perf_cfg = os.path.join( | |
| 537 os.path.abspath(os.path.dirname(sys.argv[0])), | |
| 538 current_perf_cfg_file) | |
| 514 | 539 |
| 515 config = _LoadConfigFile(path_to_perf_cfg) | 540 config = _LoadConfigFile(path_to_perf_cfg) |
| 516 config_is_valid = _ValidatePerfConfigFile(config) | 541 config_is_valid = _ValidatePerfConfigFile(config) |
| 517 | 542 |
| 518 if config and config_is_valid: | 543 if config and config_is_valid: |
| 519 return _SetupAndRunPerformanceTest(config, path_to_current_directory, | 544 return _SetupAndRunPerformanceTest( |
| 520 opts.path_to_goma) | 545 config, current_dir, opts.path_to_goma) |
| 521 | 546 |
| 522 print 'Error: Could not load config file. Double check your changes to '\ | 547 print ('Error: Could not load config file. Double check your changes to ' |
| 523 'run-bisect-perf-regression.cfg/run-perf-test.cfg for syntax errors.' | 548 'run-bisect-perf-regression.cfg or run-perf-test.cfg for syntax ' |
| 524 print | 549 'errors.\n') |
| 525 return 1 | 550 return 1 |
| 526 | 551 |
| 527 | 552 |
| 528 if __name__ == '__main__': | 553 if __name__ == '__main__': |
| 529 sys.exit(main()) | 554 sys.exit(main()) |
| OLD | NEW |