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 |