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') |
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' |
| 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(): |
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 |
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. |
340 | 356 |
341 Args: | 357 Args: |
342 config: A dict containing the parameters to pass to the script. | 358 config: A dict containing the parameters to pass to the script. |
343 working_directory: A working directory to provide to the | 359 working_directory: A working directory to provide to the |
344 bisect-perf-regression.py script, where it will store it's own copy of | 360 bisect-perf-regression.py script, where it will store it's own copy of |
345 the depot. | 361 the depot. |
346 path_to_file: Path to the bisect-perf-regression.py script. | 362 path_to_file: Path to the bisect-perf-regression.py script. |
347 path_to_goma: Path to goma directory. | 363 path_to_goma: Path to goma directory. |
348 path_to_extra_src: Path to extra source file. | 364 path_to_extra_src: Path to extra source file. |
349 dry_run: Do a dry run, skipping sync, build, and performance testing steps. | 365 dry_run: Do a dry run, skipping sync, build, and performance testing steps. |
350 | 366 |
351 Returns: | 367 Returns: |
352 0 on success, otherwise 1. | 368 An exit status code: 0 on success, otherwise 1. |
353 """ | 369 """ |
354 bisect_utils.OutputAnnotationStepStart('Config') | 370 _PrintConfigStep(config) |
355 print | |
356 for k, v in config.iteritems(): | |
357 print ' %s : %s' % (k, v) | |
358 print | |
359 bisect_utils.OutputAnnotationStepClosed() | |
360 | 371 |
361 cmd = ['python', os.path.join(path_to_file, 'bisect-perf-regression.py'), | 372 cmd = ['python', os.path.join(path_to_file, 'bisect-perf-regression.py'), |
362 '-c', config['command'], | 373 '-c', config['command'], |
363 '-g', config['good_revision'], | 374 '-g', config['good_revision'], |
364 '-b', config['bad_revision'], | 375 '-b', config['bad_revision'], |
365 '-m', config['metric'], | 376 '-m', config['metric'], |
366 '--working_directory', working_directory, | 377 '--working_directory', working_directory, |
367 '--output_buildbot_annotations'] | 378 '--output_buildbot_annotations'] |
368 | 379 |
369 if config['repeat_count']: | 380 if config['repeat_count']: |
(...skipping 10 matching lines...) Expand all Loading... |
380 | 391 |
381 cmd.extend(['--build_preference', 'ninja']) | 392 cmd.extend(['--build_preference', 'ninja']) |
382 | 393 |
383 if '--browser=cros' in config['command']: | 394 if '--browser=cros' in config['command']: |
384 cmd.extend(['--target_platform', 'cros']) | 395 cmd.extend(['--target_platform', 'cros']) |
385 | 396 |
386 if os.environ[CROS_BOARD_ENV] and os.environ[CROS_IP_ENV]: | 397 if os.environ[CROS_BOARD_ENV] and os.environ[CROS_IP_ENV]: |
387 cmd.extend(['--cros_board', os.environ[CROS_BOARD_ENV]]) | 398 cmd.extend(['--cros_board', os.environ[CROS_BOARD_ENV]]) |
388 cmd.extend(['--cros_remote_ip', os.environ[CROS_IP_ENV]]) | 399 cmd.extend(['--cros_remote_ip', os.environ[CROS_IP_ENV]]) |
389 else: | 400 else: |
390 print 'Error: Cros build selected, but BISECT_CROS_IP or'\ | 401 print ('Error: Cros build selected, but BISECT_CROS_IP or' |
391 'BISECT_CROS_BOARD undefined.' | 402 'BISECT_CROS_BOARD undefined.\n') |
392 print | |
393 return 1 | 403 return 1 |
394 | 404 |
395 if 'android' in config['command']: | 405 if 'android' in config['command']: |
396 if 'android-chrome-shell' in config['command']: | 406 if 'android-chrome-shell' in config['command']: |
397 cmd.extend(['--target_platform', 'android']) | 407 cmd.extend(['--target_platform', 'android']) |
398 elif 'android-chrome' in config['command']: | 408 elif 'android-chrome' in config['command']: |
399 cmd.extend(['--target_platform', 'android-chrome']) | 409 cmd.extend(['--target_platform', 'android-chrome']) |
400 else: | 410 else: |
401 cmd.extend(['--target_platform', 'android']) | 411 cmd.extend(['--target_platform', 'android']) |
402 | 412 |
403 if path_to_goma: | 413 if path_to_goma: |
404 # crbug.com/330900. For Windows XP platforms, GOMA service is not supported. | 414 # For Windows XP platforms, goma service is not supported. |
405 # Moreover we don't compile chrome when gs_bucket flag is set instead | 415 # Moreover we don't compile chrome when gs_bucket flag is set instead |
406 # use builds archives, therefore ignore GOMA service for Windows XP. | 416 # use builds archives, therefore ignore goma service for Windows XP. |
| 417 # See http://crbug.com/330900. |
407 if config.get('gs_bucket') and platform.release() == 'XP': | 418 if config.get('gs_bucket') and platform.release() == 'XP': |
408 print ('Goma doesn\'t have a win32 binary, therefore it is not supported ' | 419 print ('Goma doesn\'t have a win32 binary, therefore it is not supported ' |
409 'on Windows XP platform. Please refer to crbug.com/330900.') | 420 'on Windows XP platform. Please refer to crbug.com/330900.') |
410 path_to_goma = None | 421 path_to_goma = None |
411 cmd.append('--use_goma') | 422 cmd.append('--use_goma') |
412 | 423 |
413 if path_to_extra_src: | 424 if path_to_extra_src: |
414 cmd.extend(['--extra_src', path_to_extra_src]) | 425 cmd.extend(['--extra_src', path_to_extra_src]) |
415 | 426 |
416 # These flags are used to download build archives from cloud storage if | 427 # 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 | 428 # available, otherwise will post a try_job_http request to build it on |
418 # tryserver. | 429 # tryserver. |
419 if config.get('gs_bucket'): | 430 if config.get('gs_bucket'): |
420 if config.get('builder_host') and config.get('builder_port'): | 431 if config.get('builder_host') and config.get('builder_port'): |
421 cmd.extend(['--gs_bucket', config['gs_bucket'], | 432 cmd.extend(['--gs_bucket', config['gs_bucket'], |
422 '--builder_host', config['builder_host'], | 433 '--builder_host', config['builder_host'], |
423 '--builder_port', config['builder_port'] | 434 '--builder_port', config['builder_port'] |
424 ]) | 435 ]) |
425 else: | 436 else: |
426 print ('Error: Specified gs_bucket, but missing builder_host or ' | 437 print ('Error: Specified gs_bucket, but missing builder_host or ' |
427 'builder_port information in config.') | 438 'builder_port information in config.') |
428 return 1 | 439 return 1 |
429 | 440 |
430 if dry_run: | 441 if dry_run: |
431 cmd.extend(['--debug_ignore_build', '--debug_ignore_sync', | 442 cmd.extend(['--debug_ignore_build', '--debug_ignore_sync', |
432 '--debug_ignore_perf_test']) | 443 '--debug_ignore_perf_test']) |
433 cmd = [str(c) for c in cmd] | 444 cmd = [str(c) for c in cmd] |
434 | 445 |
435 with Goma(path_to_goma) as goma: | 446 with Goma(path_to_goma) as _: |
436 return_code = subprocess.call(cmd) | 447 return_code = subprocess.call(cmd) |
437 | 448 |
438 if return_code: | 449 if return_code: |
439 print 'Error: bisect-perf-regression.py returned with error %d' %\ | 450 print ('Error: bisect-perf-regression.py returned with error %d\n' |
440 return_code | 451 % return_code) |
441 print | |
442 | 452 |
443 return return_code | 453 return return_code |
444 | 454 |
445 | 455 |
446 def main(): | 456 def _PrintConfigStep(config): |
| 457 """Prints out the given config, along with Buildbot annotations.""" |
| 458 bisect_utils.OutputAnnotationStepStart('Config') |
| 459 print |
| 460 for k, v in config.iteritems(): |
| 461 print ' %s : %s' % (k, v) |
| 462 print |
| 463 bisect_utils.OutputAnnotationStepClosed() |
447 | 464 |
| 465 |
| 466 def _OptionParser(): |
| 467 """Returns the options parser for run-bisect-perf-regression.py.""" |
448 usage = ('%prog [options] [-- chromium-options]\n' | 468 usage = ('%prog [options] [-- chromium-options]\n' |
449 'Used by a trybot to run the bisection script using the parameters' | 469 'Used by a trybot to run the bisection script using the parameters' |
450 ' provided in the run-bisect-perf-regression.cfg file.') | 470 ' provided in the run-bisect-perf-regression.cfg file.') |
451 | |
452 parser = optparse.OptionParser(usage=usage) | 471 parser = optparse.OptionParser(usage=usage) |
453 parser.add_option('-w', '--working_directory', | 472 parser.add_option('-w', '--working_directory', |
454 type='str', | 473 type='str', |
455 help='A working directory to supply to the bisection ' | 474 help='A working directory to supply to the bisection ' |
456 'script, which will use it as the location to checkout ' | 475 'script, which will use it as the location to checkout ' |
457 'a copy of the chromium depot.') | 476 'a copy of the chromium depot.') |
458 parser.add_option('-p', '--path_to_goma', | 477 parser.add_option('-p', '--path_to_goma', |
459 type='str', | 478 type='str', |
460 help='Path to goma directory. If this is supplied, goma ' | 479 help='Path to goma directory. If this is supplied, goma ' |
461 'builds will be enabled.') | 480 'builds will be enabled.') |
462 parser.add_option('--path_to_config', | 481 parser.add_option('--path_to_config', |
463 type='str', | 482 type='str', |
464 help='Path to the config file to use. If this is supplied, ' | 483 help='Path to the config file to use. If this is supplied, ' |
465 'the bisect script will use this to override the default ' | 484 'the bisect script will use this to override the default ' |
466 'config file path. The script will attempt to load it ' | 485 'config file path. The script will attempt to load it ' |
467 'as a bisect config first, then a perf config.') | 486 'as a bisect config first, then a perf config.') |
468 parser.add_option('--extra_src', | 487 parser.add_option('--extra_src', |
469 type='str', | 488 type='str', |
470 help='Path to extra source file. If this is supplied, ' | 489 help='Path to extra source file. If this is supplied, ' |
471 'bisect script will use this to override default behavior.') | 490 'bisect script will use this to override default behavior.') |
472 parser.add_option('--dry_run', | 491 parser.add_option('--dry_run', |
473 action="store_true", | 492 action="store_true", |
474 help='The script will perform the full bisect, but ' | 493 help='The script will perform the full bisect, but ' |
475 'without syncing, building, or running the performance ' | 494 'without syncing, building, or running the performance ' |
476 'tests.') | 495 'tests.') |
477 (opts, args) = parser.parse_args() | 496 return parser |
478 | 497 |
479 path_to_current_directory = os.path.abspath(os.path.dirname(sys.argv[0])) | |
480 | 498 |
481 # If they've specified their own config file, use that instead. | 499 def main(): |
| 500 """Entry point for run-bisect-perf-regression.py. |
| 501 |
| 502 Reads the config file, and then tries to either bisect a regression or |
| 503 just run a performance test, depending on the particular config parameters |
| 504 specified in the config file. |
| 505 """ |
| 506 |
| 507 parser = _OptionParser() |
| 508 opts, _ = parser.parse_args() |
| 509 |
| 510 current_dir = os.path.abspath(os.path.dirname(sys.argv[0])) |
| 511 |
| 512 # Use the default config file path unless one was specified. |
| 513 config_path = os.path.join(current_dir, BISECT_REGRESSION_CONFIG) |
482 if opts.path_to_config: | 514 if opts.path_to_config: |
483 path_to_bisect_cfg = opts.path_to_config | 515 config_path = opts.path_to_config |
484 else: | 516 config = _LoadConfigFile(config_path) |
485 path_to_bisect_cfg = os.path.join(path_to_current_directory, | |
486 'run-bisect-perf-regression.cfg') | |
487 | 517 |
488 config = _LoadConfigFile(path_to_bisect_cfg) | 518 # Check if the config is valid for running bisect job. |
489 | |
490 # Check if the config is valid. | |
491 config_is_valid = _ValidateBisectConfigFile(config) | 519 config_is_valid = _ValidateBisectConfigFile(config) |
492 | 520 |
493 if config and config_is_valid: | 521 if config and config_is_valid: |
494 if not opts.working_directory: | 522 if not opts.working_directory: |
495 print 'Error: missing required parameter: --working_directory' | 523 print 'Error: missing required parameter: --working_directory\n' |
496 print | |
497 parser.print_help() | 524 parser.print_help() |
498 return 1 | 525 return 1 |
499 | 526 |
500 return _RunBisectionScript(config, opts.working_directory, | 527 return _RunBisectionScript( |
501 path_to_current_directory, opts.path_to_goma, opts.extra_src, | 528 config, opts.working_directory, current_dir, |
502 opts.dry_run) | 529 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 | 530 |
507 for current_perf_cfg_file in perf_cfg_files: | 531 # If it wasn't valid for running a bisect, then maybe the user wanted |
508 if opts.path_to_config: | 532 # to run a perf test instead of a bisect job. Try reading any possible |
509 path_to_perf_cfg = opts.path_to_config | 533 # perf test config files. |
510 else: | 534 perf_cfg_files = [RUN_TEST_CONFIG, WEBKIT_RUN_TEST_CONFIG] |
511 path_to_perf_cfg = os.path.join( | 535 for current_perf_cfg_file in perf_cfg_files: |
512 os.path.abspath(os.path.dirname(sys.argv[0])), | 536 if opts.path_to_config: |
513 current_perf_cfg_file) | 537 path_to_perf_cfg = opts.path_to_config |
| 538 else: |
| 539 path_to_perf_cfg = os.path.join( |
| 540 os.path.abspath(os.path.dirname(sys.argv[0])), |
| 541 current_perf_cfg_file) |
514 | 542 |
515 config = _LoadConfigFile(path_to_perf_cfg) | 543 config = _LoadConfigFile(path_to_perf_cfg) |
516 config_is_valid = _ValidatePerfConfigFile(config) | 544 config_is_valid = _ValidatePerfConfigFile(config) |
517 | 545 |
518 if config and config_is_valid: | 546 if config and config_is_valid: |
519 return _SetupAndRunPerformanceTest(config, path_to_current_directory, | 547 return _SetupAndRunPerformanceTest( |
520 opts.path_to_goma) | 548 config, current_dir, opts.path_to_goma) |
521 | 549 |
522 print 'Error: Could not load config file. Double check your changes to '\ | 550 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.' | 551 'run-bisect-perf-regression.cfg or run-perf-test.cfg for syntax ' |
524 print | 552 'errors.\n') |
525 return 1 | 553 return 1 |
526 | 554 |
527 | 555 |
528 if __name__ == '__main__': | 556 if __name__ == '__main__': |
529 sys.exit(main()) | 557 sys.exit(main()) |
OLD | NEW |