Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(516)

Side by Side Diff: tools/run-bisect-perf-regression.py

Issue 27165006: First pass performance try bot. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 12
13 """ 13 """
14 14
15 import imp 15 import imp
16 import optparse 16 import optparse
17 import os 17 import os
18 import subprocess 18 import subprocess
19 import sys 19 import sys
20 import traceback 20 import traceback
21 21
22 import bisect_utils
23 bisect = imp.load_source('bisect-perf-regression',
24 os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])),
25 'bisect-perf-regression.py'))
26
27
22 CROS_BOARD_ENV = 'BISECT_CROS_BOARD' 28 CROS_BOARD_ENV = 'BISECT_CROS_BOARD'
23 CROS_IP_ENV = 'BISECT_CROS_IP' 29 CROS_IP_ENV = 'BISECT_CROS_IP'
24 30
25 def LoadConfigFile(path_to_file): 31 def _LoadConfigFile(path_to_file):
26 """Attempts to load the file 'run-bisect-perf-regression.cfg' as a module 32 """Attempts to load the specified config file as a module
27 and grab the global config dict. 33 and grab the global config dict.
28 34
29 Args: 35 Args:
30 path_to_file: Path to the run-bisect-perf-regression.cfg file. 36 path_to_file: Path to the file.
31 37
32 Returns: 38 Returns:
33 The config dict which should be formatted as follows: 39 The config dict which should be formatted as follows:
34 {'command': string, 'good_revision': string, 'bad_revision': string 40 {'command': string, 'good_revision': string, 'bad_revision': string
35 'metric': string}. 41 'metric': string, etc...}.
36 Returns None on failure. 42 Returns None on failure.
37 """ 43 """
38 try: 44 try:
39 local_vars = {} 45 local_vars = {}
40 execfile(os.path.join(path_to_file, 'run-bisect-perf-regression.cfg'), 46 execfile(path_to_file, local_vars)
41 local_vars)
42 47
43 return local_vars['config'] 48 return local_vars['config']
44 except: 49 except:
45 print 50 print
46 traceback.print_exc() 51 traceback.print_exc()
47 print 52 print
48 return None 53 return None
49 54
50 55
51 def RunBisectionScript(config, working_directory, path_to_file, path_to_goma): 56 def _GetGOMAExecutable(path_to_goma):
tonyg 2013/10/17 01:01:32 I like the refactor so far, but you've got an easy
shatch 2013/10/17 21:59:08 Neat, didn't know about that. Planning on making a
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
63 def _SetupAndStartGOMA(path_to_goma):
64 """Sets up GOMA and launches it.
65
66 Args:
67 path_to_goma: Path to goma directory.
68
69 Returns:
70 True if successful."""
71 abs_path_to_goma = os.path.abspath(path_to_goma)
72 goma_file = _GetGOMAExecutable(abs_path_to_goma)
73
74 if os.name == 'nt':
75 os.environ['CC'] = os.path.join(abs_path_to_goma, 'gomacc.exe') + ' cl.exe'
76 os.environ['CXX'] = os.path.join(abs_path_to_goma, 'gomacc.exe') + ' cl.exe'
77 else:
78 os.environ['PATH'] = os.pathsep.join([abs_path_to_goma, os.environ['PATH']])
79
80 # Sometimes goma is lingering around if something went bad on a previous
81 # run. Stop it before starting a new process. Can ignore the return code
82 # since it will return an error if it wasn't running.
83 _StopGOMA(path_to_goma)
84
85 return not subprocess.call([goma_file, 'start'])
86
87
88 def _StopGOMA(path_to_goma):
89 abs_path_to_goma = os.path.abspath(path_to_goma)
90 goma_file = _GetGOMAExecutable(abs_path_to_goma)
91 subprocess.call([goma_file, 'stop'])
92
93
94 def _OutputFailedResults(text_to_print):
95 bisect_utils.OutputAnnotationStepStart('Results - Failed')
96 print
97 print text_to_print
98 print
99 bisect_utils.OutputAnnotationStepClosed()
100
101
102 def _CreateBisectOptionsFromConfig(config):
103 opts_dict = {}
104 opts_dict['command'] = config['command']
105 opts_dict['metric'] = config['metric']
106
107 if config['repeat_count']:
108 opts_dict['repeat_test_count'] = int(config['repeat_count'])
109
110 if config['truncate_percent']:
111 opts_dict['truncate_percent'] = int(config['truncate_percent'])
112
113 if config['max_time_minutes']:
114 opts_dict['max_time_minutes'] = int(config['max_time_minutes'])
115
116 if config.has_key('use_goma'):
117 opts_dict['use_goma'] = config['use_goma']
118
119 opts_dict['build_preference'] = 'ninja'
120 opts_dict['output_buildbot_annotations'] = True
121
122 if '--browser=cros' in config['command']:
123 opts_dict['target_platform'] = 'cros'
124
125 if os.environ[CROS_BOARD_ENV] and os.environ[CROS_IP_ENV]:
126 opts_dict['cros_board'] = os.environ[CROS_BOARD_ENV]
127 opts_dict['cros_remote_ip'] = os.environ[CROS_IP_ENV]
128 else:
129 raise RuntimeError('Cros build selected, but BISECT_CROS_IP or'
130 'BISECT_CROS_BOARD undefined.')
131 elif 'android' in config['command']:
132 opts_dict['target_platform'] = 'android'
133
134 return bisect.BisectOptions.FromDict(opts_dict)
135
136
137 def _RunPerformancetest(config, path_to_file):
tonyg 2013/10/17 01:01:32 Capitalize Test?
shatch 2013/10/17 21:59:08 Done.
138 # Bisect script expects to be run from src
139 os.chdir(os.path.join(path_to_file, '..'))
140
141 bisect_utils.OutputAnnotationStepStart('Building With Patch')
142
143 opts = _CreateBisectOptionsFromConfig(config)
144 b = bisect.BisectPerformanceMetrics(None, opts)
145
146 if bisect_utils.RunGClient(['runhooks']):
147 raise RuntimeError('Failed to run gclient runhooks')
148
149 if not b.BuildCurrentRevision('chromium'):
150 raise RuntimeError('Patched version failed to build.')
151
152 bisect_utils.OutputAnnotationStepClosed()
153 bisect_utils.OutputAnnotationStepStart('Running With Patch')
154
155 results_with_patch = b.RunPerformanceTestAndParseResults(
156 opts.command, opts.metric, reset_on_first_run=True)
157
158 if results_with_patch[1]:
159 raise RuntimeError('Patched version failed to run performance test.')
160
161 bisect_utils.OutputAnnotationStepClosed()
162
163 bisect_utils.OutputAnnotationStepStart('Reverting Patch')
164 if bisect_utils.RunGClient(['revert']):
165 raise RuntimeError('Failed to run gclient runhooks')
166 bisect_utils.OutputAnnotationStepClosed()
167
168 bisect_utils.OutputAnnotationStepStart('Building Without Patch')
169
170 if bisect_utils.RunGClient(['runhooks']):
171 raise RuntimeError('Failed to run gclient runhooks')
172
173 if not b.BuildCurrentRevision('chromium'):
174 raise RuntimeError('Unpatched version failed to build.')
175
176 bisect_utils.OutputAnnotationStepClosed()
177 bisect_utils.OutputAnnotationStepStart('Running Without Patch')
178
179 results_without_patch = b.RunPerformanceTestAndParseResults(
180 opts.command, opts.metric, upload_on_last_run=True)
181
182 if results_without_patch[1]:
183 raise RuntimeError('Unpatched version failed to run performance test.')
184
185 # Find the link to the cloud stored results file.
186 output = results_without_patch[2]
187 cloud_file_link = [t for t in output.splitlines() if 'View online at' in t]
tonyg 2013/10/17 01:01:32 Just realized a minor wrinkle. It won't be obvious
shatch 2013/10/17 21:59:08 Sure, I'll get a separate CL going to pass labels
188 if cloud_file_link:
189 cloud_file_link = cloud_file_link[0]
190 else:
191 cloud_file_link = ''
192
193 bisect_utils.OutputAnnotationStepClosed()
194 if cloud_file_link:
195 bisect_utils.OutputAnnotationStepStart('Results - %s' % cloud_file_link)
tonyg 2013/10/17 01:01:32 I think what we want is: OutputAnnotationStepStar
shatch 2013/10/17 21:59:08 Done.
196 else:
197 bisect_utils.OutputAnnotationStepStart('Results')
198 print ' %s %s %s' % (''.center(10, ' '), 'Mean'.center(20, ' '),
199 'Std. Error'.center(20, ' '))
200 print ' %s %s %s' % ('Patch'.center(10, ' '),
201 ('%.02f' % results_with_patch[0]['mean']).center(20, ' '),
202 ('%.02f' % results_with_patch[0]['std_err']).center(20, ' '))
203 print ' %s %s %s' % ('No Patch'.center(10, ' '),
204 ('%.02f' % results_without_patch[0]['mean']).center(20, ' '),
205 ('%.02f' % results_without_patch[0]['std_err']).center(20, ' '))
206 print
207 print cloud_file_link
208 print
209 bisect_utils.OutputAnnotationStepClosed()
210
211
212 def _SetupAndRunPerformanceTest(config, path_to_file, path_to_goma):
213 """Attempts to build and run the current revision with and without the
214 current patch, with the parameters passed in.
215
216 Args:
217 config: The config read from run-perf-test.cfg.
218 path_to_file: Path to the bisect-perf-regression.py script.
219 path_to_goma: Path to goma directory.
220
221 Returns:
222 0 on success, otherwise 1.
223 """
224 if path_to_goma:
225 config['use_goma'] = True
226 if not _SetupAndStartGOMA(path_to_goma):
227 _OutputFailedResults('Error: goma failed to start.')
228 return 1
229
230 cwd = os.getcwd()
231 try:
232 _RunPerformancetest(config, path_to_file)
233 return 0
234 except RuntimeError, e:
235 bisect_utils.OutputAnnotationStepClosed()
236 _OutputFailedResults('Error: %s' % e.message)
237 return 1
238 finally:
239 os.chdir(cwd)
240 if path_to_goma:
241 _StopGOMA(path_to_goma)
242
243
244 def _RunBisectionScript(config, working_directory, path_to_file, path_to_goma):
52 """Attempts to execute src/tools/bisect-perf-regression.py with the parameters 245 """Attempts to execute src/tools/bisect-perf-regression.py with the parameters
53 passed in. 246 passed in.
54 247
55 Args: 248 Args:
56 config: A dict containing the parameters to pass to the script. 249 config: A dict containing the parameters to pass to the script.
57 working_directory: A working directory to provide to the 250 working_directory: A working directory to provide to the
58 bisect-perf-regression.py script, where it will store it's own copy of 251 bisect-perf-regression.py script, where it will store it's own copy of
59 the depot. 252 the depot.
60 path_to_file: Path to the bisect-perf-regression.py script. 253 path_to_file: Path to the bisect-perf-regression.py script.
61 path_to_goma: Path to goma directory. 254 path_to_goma: Path to goma directory.
(...skipping 29 matching lines...) Expand all
91 cmd.extend(['--cros_remote_ip', os.environ[CROS_IP_ENV]]) 284 cmd.extend(['--cros_remote_ip', os.environ[CROS_IP_ENV]])
92 else: 285 else:
93 print 'Error: Cros build selected, but BISECT_CROS_IP or'\ 286 print 'Error: Cros build selected, but BISECT_CROS_IP or'\
94 'BISECT_CROS_BOARD undefined.' 287 'BISECT_CROS_BOARD undefined.'
95 print 288 print
96 return 1 289 return 1
97 290
98 if 'android' in config['command']: 291 if 'android' in config['command']:
99 cmd.extend(['--target_platform', 'android']) 292 cmd.extend(['--target_platform', 'android'])
100 293
101 goma_file = ''
102 if path_to_goma: 294 if path_to_goma:
103 path_to_goma = os.path.abspath(path_to_goma) 295 if not _SetupAndStartGOMA(path_to_goma):
104 296 print 'Error: goma failed to start.'
105 if os.name == 'nt': 297 print
106 os.environ['CC'] = os.path.join(path_to_goma, 'gomacc.exe') + ' cl.exe' 298 return 1
107 os.environ['CXX'] = os.path.join(path_to_goma, 'gomacc.exe') + ' cl.exe'
108 goma_file = os.path.join(path_to_goma, 'goma_ctl.bat')
109 else:
110 os.environ['PATH'] = os.pathsep.join([path_to_goma, os.environ['PATH']])
111 goma_file = os.path.join(path_to_goma, 'goma_ctl.sh')
112 299
113 cmd.append('--use_goma') 300 cmd.append('--use_goma')
114 301
115 # Sometimes goma is lingering around if something went bad on a previous
116 # run. Stop it before starting a new process. Can ignore the return code
117 # since it will return an error if it wasn't running.
118 subprocess.call([goma_file, 'stop'])
119
120 return_code = subprocess.call([goma_file, 'start'])
121 if return_code:
122 print 'Error: goma failed to start.'
123 print
124 return return_code
125
126 cmd = [str(c) for c in cmd] 302 cmd = [str(c) for c in cmd]
127 303
128 return_code = subprocess.call(cmd) 304 return_code = subprocess.call(cmd)
129 305
130 if path_to_goma: 306 if path_to_goma:
131 subprocess.call([goma_file, 'stop']) 307 _StopGOMA(path_to_goma)
132 308
133 if return_code: 309 if return_code:
134 print 'Error: bisect-perf-regression.py returned with error %d' %\ 310 print 'Error: bisect-perf-regression.py returned with error %d' %\
135 return_code 311 return_code
136 print 312 print
137 313
138 return return_code 314 return return_code
139 315
140 316
141 def main(): 317 def main():
142 318
143 usage = ('%prog [options] [-- chromium-options]\n' 319 usage = ('%prog [options] [-- chromium-options]\n'
144 'Used by a trybot to run the bisection script using the parameters' 320 'Used by a trybot to run the bisection script using the parameters'
145 ' provided in the run-bisect-perf-regression.cfg file.') 321 ' provided in the run-bisect-perf-regression.cfg file.')
146 322
147 parser = optparse.OptionParser(usage=usage) 323 parser = optparse.OptionParser(usage=usage)
148 parser.add_option('-w', '--working_directory', 324 parser.add_option('-w', '--working_directory',
149 type='str', 325 type='str',
150 help='A working directory to supply to the bisection ' 326 help='A working directory to supply to the bisection '
151 'script, which will use it as the location to checkout ' 327 'script, which will use it as the location to checkout '
152 'a copy of the chromium depot.') 328 'a copy of the chromium depot.')
153 parser.add_option('-p', '--path_to_goma', 329 parser.add_option('-p', '--path_to_goma',
154 type='str', 330 type='str',
155 help='Path to goma directory. If this is supplied, goma ' 331 help='Path to goma directory. If this is supplied, goma '
156 'builds will be enabled.') 332 'builds will be enabled.')
157 (opts, args) = parser.parse_args() 333 (opts, args) = parser.parse_args()
158 334
159 if not opts.working_directory: 335 path_to_current_directory = os.path.abspath(os.path.dirname(sys.argv[0]))
160 print 'Error: missing required parameter: --working_directory' 336 path_to_bisect_cfg = os.path.join(path_to_current_directory,
161 print 337 'run-bisect-perf-regression.cfg')
162 parser.print_help()
163 return 1
164 338
165 path_to_file = os.path.abspath(os.path.dirname(sys.argv[0])) 339 config = _LoadConfigFile(path_to_bisect_cfg)
166 340
167 config = LoadConfigFile(path_to_file) 341 # Check if the config is empty
168 if not config: 342 config_has_values = [v for v in config.values() if v]
169 print 'Error: Could not load config file. Double check your changes to '\
170 'run-bisect-perf-regression.cfg for syntax errors.'
171 print
172 return 1
173 343
174 return RunBisectionScript(config, opts.working_directory, path_to_file, 344 if config and config_has_values:
175 opts.path_to_goma) 345 if not opts.working_directory:
346 print 'Error: missing required parameter: --working_directory'
347 print
348 parser.print_help()
349 return 1
350
351 return _RunBisectionScript(config, opts.working_directory,
352 path_to_current_directory, opts.path_to_goma)
353 else:
354 path_to_perf_cfg = os.path.join(
355 os.path.abspath(os.path.dirname(sys.argv[0])), 'run-perf-test.cfg')
356
357 config = _LoadConfigFile(path_to_perf_cfg)
358
359 if config:
360 return _SetupAndRunPerformanceTest(config, path_to_current_directory,
361 opts.path_to_goma)
362 else:
363 print 'Error: Could not load config file. Double check your changes to '\
364 'run-bisect-perf-regression.cfg for syntax errors.'
365 print
366 return 1
176 367
177 368
178 if __name__ == '__main__': 369 if __name__ == '__main__':
179 sys.exit(main()) 370 sys.exit(main())
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698