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

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: Changes from review. 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
« no previous file with comments | « tools/bisect_utils.py ('k') | tools/run-perf-test.cfg » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
26 """Attempts to load the file 'run-bisect-perf-regression.cfg' as a module 32 class Goma(object):
33
34 def __init__(self, path_to_goma):
35 self._abs_path_to_goma = None
36 self._abs_path_to_goma_file = None
37 if path_to_goma:
38 self._abs_path_to_goma = os.path.abspath(path_to_goma)
39 self._abs_path_to_goma_file = self._GetExecutablePath(
40 self._abs_path_to_goma)
41
42 def __enter__(self):
43 if self._HasGOMAPath():
44 self._SetupAndStart()
45 return self
46
47 def __exit__(self, *_):
48 if self._HasGOMAPath():
49 self._Stop()
50
51 def _HasGOMAPath(self):
52 return bool(self._abs_path_to_goma)
53
54 def _GetExecutablePath(self, path_to_goma):
55 if os.name == 'nt':
56 return os.path.join(path_to_goma, 'goma_ctl.bat')
57 else:
58 return os.path.join(path_to_goma, 'goma_ctl.sh')
59
60 def _SetupEnvVars(self):
61 if os.name == 'nt':
62 os.environ['CC'] = (os.path.join(self._abs_path_to_goma, 'gomacc.exe') +
63 ' cl.exe')
64 os.environ['CXX'] = (os.path.join(self._abs_path_to_goma, 'gomacc.exe') +
65 ' cl.exe')
66 else:
67 os.environ['PATH'] = os.pathsep.join([self._abs_path_to_goma,
68 os.environ['PATH']])
69
70 def _SetupAndStart(self):
71 """Sets up GOMA and launches it.
72
73 Args:
74 path_to_goma: Path to goma directory.
75
76 Returns:
77 True if successful."""
78 self._SetupEnvVars()
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 self._Stop()
84
85 if subprocess.call([self._abs_path_to_goma_file, 'start']):
86 raise RuntimeError('GOMA failed to start.')
87
88 def _Stop(self):
89 subprocess.call([self._abs_path_to_goma_file, 'stop'])
90
91
92
93 def _LoadConfigFile(path_to_file):
94 """Attempts to load the specified config file as a module
27 and grab the global config dict. 95 and grab the global config dict.
28 96
29 Args: 97 Args:
30 path_to_file: Path to the run-bisect-perf-regression.cfg file. 98 path_to_file: Path to the file.
31 99
32 Returns: 100 Returns:
33 The config dict which should be formatted as follows: 101 The config dict which should be formatted as follows:
34 {'command': string, 'good_revision': string, 'bad_revision': string 102 {'command': string, 'good_revision': string, 'bad_revision': string
35 'metric': string}. 103 'metric': string, etc...}.
36 Returns None on failure. 104 Returns None on failure.
37 """ 105 """
38 try: 106 try:
39 local_vars = {} 107 local_vars = {}
40 execfile(os.path.join(path_to_file, 'run-bisect-perf-regression.cfg'), 108 execfile(path_to_file, local_vars)
41 local_vars)
42 109
43 return local_vars['config'] 110 return local_vars['config']
44 except: 111 except:
45 print 112 print
46 traceback.print_exc() 113 traceback.print_exc()
47 print 114 print
48 return None 115 return None
49 116
50 117
51 def RunBisectionScript(config, working_directory, path_to_file, path_to_goma): 118 def _OutputFailedResults(text_to_print):
119 bisect_utils.OutputAnnotationStepStart('Results - Failed')
120 print
121 print text_to_print
122 print
123 bisect_utils.OutputAnnotationStepClosed()
124
125
126 def _CreateBisectOptionsFromConfig(config):
127 opts_dict = {}
128 opts_dict['command'] = config['command']
129 opts_dict['metric'] = config['metric']
130
131 if config['repeat_count']:
132 opts_dict['repeat_test_count'] = int(config['repeat_count'])
133
134 if config['truncate_percent']:
135 opts_dict['truncate_percent'] = int(config['truncate_percent'])
136
137 if config['max_time_minutes']:
138 opts_dict['max_time_minutes'] = int(config['max_time_minutes'])
139
140 if config.has_key('use_goma'):
141 opts_dict['use_goma'] = config['use_goma']
142
143 opts_dict['build_preference'] = 'ninja'
144 opts_dict['output_buildbot_annotations'] = True
145
146 if '--browser=cros' in config['command']:
147 opts_dict['target_platform'] = 'cros'
148
149 if os.environ[CROS_BOARD_ENV] and os.environ[CROS_IP_ENV]:
150 opts_dict['cros_board'] = os.environ[CROS_BOARD_ENV]
151 opts_dict['cros_remote_ip'] = os.environ[CROS_IP_ENV]
152 else:
153 raise RuntimeError('Cros build selected, but BISECT_CROS_IP or'
154 'BISECT_CROS_BOARD undefined.')
155 elif 'android' in config['command']:
156 opts_dict['target_platform'] = 'android'
157
158 return bisect.BisectOptions.FromDict(opts_dict)
159
160
161 def _RunPerformanceTest(config, path_to_file):
162 # Bisect script expects to be run from src
163 os.chdir(os.path.join(path_to_file, '..'))
164
165 bisect_utils.OutputAnnotationStepStart('Building With Patch')
166
167 opts = _CreateBisectOptionsFromConfig(config)
168 b = bisect.BisectPerformanceMetrics(None, opts)
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('Patched version failed to build.')
175
176 bisect_utils.OutputAnnotationStepClosed()
177 bisect_utils.OutputAnnotationStepStart('Running With Patch')
178
179 results_with_patch = b.RunPerformanceTestAndParseResults(
180 opts.command, opts.metric, reset_on_first_run=True, results_label='Patch')
181
182 if results_with_patch[1]:
183 raise RuntimeError('Patched version failed to run performance test.')
184
185 bisect_utils.OutputAnnotationStepClosed()
186
187 bisect_utils.OutputAnnotationStepStart('Reverting Patch')
188 if bisect_utils.RunGClient(['revert']):
189 raise RuntimeError('Failed to run gclient runhooks')
190 bisect_utils.OutputAnnotationStepClosed()
191
192 bisect_utils.OutputAnnotationStepStart('Building Without Patch')
193
194 if bisect_utils.RunGClient(['runhooks']):
195 raise RuntimeError('Failed to run gclient runhooks')
196
197 if not b.BuildCurrentRevision('chromium'):
198 raise RuntimeError('Unpatched version failed to build.')
199
200 bisect_utils.OutputAnnotationStepClosed()
201 bisect_utils.OutputAnnotationStepStart('Running Without Patch')
202
203 results_without_patch = b.RunPerformanceTestAndParseResults(
204 opts.command, opts.metric, upload_on_last_run=True, results_label='ToT')
205
206 if results_without_patch[1]:
207 raise RuntimeError('Unpatched version failed to run performance test.')
208
209 # Find the link to the cloud stored results file.
210 output = results_without_patch[2]
211 cloud_file_link = [t for t in output.splitlines()
212 if 'storage.googleapis.com/chromium-telemetry/html-results/' in t]
213 if cloud_file_link:
214 cloud_file_link = cloud_file_link[0]
215 else:
216 cloud_file_link = ''
217
218 # Calculate the % difference in the means of the 2 runs.
219 percent_diff_in_means = (results_with_patch[0]['mean'] /
220 max(0.0001, results_without_patch[0]['mean'])) * 100.0 - 100.0
221 std_err = bisect.CalculatePooledStandardError(
222 [results_with_patch[0]['values'], results_without_patch[0]['values']])
223
224 bisect_utils.OutputAnnotationStepClosed()
225 bisect_utils.OutputAnnotationStepStart('Results - %.02f +- %0.02f delta' %
226 (percent_diff_in_means, std_err))
227 print ' %s %s %s' % (''.center(10, ' '), 'Mean'.center(20, ' '),
228 'Std. Error'.center(20, ' '))
229 print ' %s %s %s' % ('Patch'.center(10, ' '),
230 ('%.02f' % results_with_patch[0]['mean']).center(20, ' '),
231 ('%.02f' % results_with_patch[0]['std_err']).center(20, ' '))
232 print ' %s %s %s' % ('No Patch'.center(10, ' '),
233 ('%.02f' % results_without_patch[0]['mean']).center(20, ' '),
234 ('%.02f' % results_without_patch[0]['std_err']).center(20, ' '))
235 if cloud_file_link:
236 bisect_utils.OutputAnnotationStepLink('HTML Results', cloud_file_link)
237 bisect_utils.OutputAnnotationStepClosed()
238
239
240 def _SetupAndRunPerformanceTest(config, path_to_file, path_to_goma):
241 """Attempts to build and run the current revision with and without the
242 current patch, with the parameters passed in.
243
244 Args:
245 config: The config read from run-perf-test.cfg.
246 path_to_file: Path to the bisect-perf-regression.py script.
247 path_to_goma: Path to goma directory.
248
249 Returns:
250 0 on success, otherwise 1.
251 """
252 try:
253 with Goma(path_to_goma) as goma:
254 config['use_goma'] = bool(path_to_goma)
255 _RunPerformanceTest(config, path_to_file)
256 return 0
257 except RuntimeError, e:
258 bisect_utils.OutputAnnotationStepClosed()
259 _OutputFailedResults('Error: %s' % e.message)
260 return 1
261
262
263 def _RunBisectionScript(config, working_directory, path_to_file, path_to_goma):
52 """Attempts to execute src/tools/bisect-perf-regression.py with the parameters 264 """Attempts to execute src/tools/bisect-perf-regression.py with the parameters
53 passed in. 265 passed in.
54 266
55 Args: 267 Args:
56 config: A dict containing the parameters to pass to the script. 268 config: A dict containing the parameters to pass to the script.
57 working_directory: A working directory to provide to the 269 working_directory: A working directory to provide to the
58 bisect-perf-regression.py script, where it will store it's own copy of 270 bisect-perf-regression.py script, where it will store it's own copy of
59 the depot. 271 the depot.
60 path_to_file: Path to the bisect-perf-regression.py script. 272 path_to_file: Path to the bisect-perf-regression.py script.
61 path_to_goma: Path to goma directory. 273 path_to_goma: Path to goma directory.
(...skipping 29 matching lines...) Expand all
91 cmd.extend(['--cros_remote_ip', os.environ[CROS_IP_ENV]]) 303 cmd.extend(['--cros_remote_ip', os.environ[CROS_IP_ENV]])
92 else: 304 else:
93 print 'Error: Cros build selected, but BISECT_CROS_IP or'\ 305 print 'Error: Cros build selected, but BISECT_CROS_IP or'\
94 'BISECT_CROS_BOARD undefined.' 306 'BISECT_CROS_BOARD undefined.'
95 print 307 print
96 return 1 308 return 1
97 309
98 if 'android' in config['command']: 310 if 'android' in config['command']:
99 cmd.extend(['--target_platform', 'android']) 311 cmd.extend(['--target_platform', 'android'])
100 312
101 goma_file = ''
102 if path_to_goma: 313 if path_to_goma:
103 path_to_goma = os.path.abspath(path_to_goma)
104
105 if os.name == 'nt':
106 os.environ['CC'] = os.path.join(path_to_goma, 'gomacc.exe') + ' cl.exe'
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
113 cmd.append('--use_goma') 314 cmd.append('--use_goma')
114 315
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] 316 cmd = [str(c) for c in cmd]
127 317
128 return_code = subprocess.call(cmd) 318 with Goma(path_to_goma) as goma:
129 319 return_code = subprocess.call(cmd)
130 if path_to_goma:
131 subprocess.call([goma_file, 'stop'])
132 320
133 if return_code: 321 if return_code:
134 print 'Error: bisect-perf-regression.py returned with error %d' %\ 322 print 'Error: bisect-perf-regression.py returned with error %d' %\
135 return_code 323 return_code
136 print 324 print
137 325
138 return return_code 326 return return_code
139 327
140 328
141 def main(): 329 def main():
142 330
143 usage = ('%prog [options] [-- chromium-options]\n' 331 usage = ('%prog [options] [-- chromium-options]\n'
144 'Used by a trybot to run the bisection script using the parameters' 332 'Used by a trybot to run the bisection script using the parameters'
145 ' provided in the run-bisect-perf-regression.cfg file.') 333 ' provided in the run-bisect-perf-regression.cfg file.')
146 334
147 parser = optparse.OptionParser(usage=usage) 335 parser = optparse.OptionParser(usage=usage)
148 parser.add_option('-w', '--working_directory', 336 parser.add_option('-w', '--working_directory',
149 type='str', 337 type='str',
150 help='A working directory to supply to the bisection ' 338 help='A working directory to supply to the bisection '
151 'script, which will use it as the location to checkout ' 339 'script, which will use it as the location to checkout '
152 'a copy of the chromium depot.') 340 'a copy of the chromium depot.')
153 parser.add_option('-p', '--path_to_goma', 341 parser.add_option('-p', '--path_to_goma',
154 type='str', 342 type='str',
155 help='Path to goma directory. If this is supplied, goma ' 343 help='Path to goma directory. If this is supplied, goma '
156 'builds will be enabled.') 344 'builds will be enabled.')
157 (opts, args) = parser.parse_args() 345 (opts, args) = parser.parse_args()
158 346
159 if not opts.working_directory: 347 path_to_current_directory = os.path.abspath(os.path.dirname(sys.argv[0]))
160 print 'Error: missing required parameter: --working_directory' 348 path_to_bisect_cfg = os.path.join(path_to_current_directory,
161 print 349 'run-bisect-perf-regression.cfg')
162 parser.print_help()
163 return 1
164 350
165 path_to_file = os.path.abspath(os.path.dirname(sys.argv[0])) 351 config = _LoadConfigFile(path_to_bisect_cfg)
166 352
167 config = LoadConfigFile(path_to_file) 353 # Check if the config is empty
168 if not config: 354 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 355
174 return RunBisectionScript(config, opts.working_directory, path_to_file, 356 if config and config_has_values:
175 opts.path_to_goma) 357 if not opts.working_directory:
358 print 'Error: missing required parameter: --working_directory'
359 print
360 parser.print_help()
361 return 1
362
363 return _RunBisectionScript(config, opts.working_directory,
364 path_to_current_directory, opts.path_to_goma)
365 else:
366 path_to_perf_cfg = os.path.join(
367 os.path.abspath(os.path.dirname(sys.argv[0])), 'run-perf-test.cfg')
368
369 config = _LoadConfigFile(path_to_perf_cfg)
370
371 if config:
372 return _SetupAndRunPerformanceTest(config, path_to_current_directory,
373 opts.path_to_goma)
374 else:
375 print 'Error: Could not load config file. Double check your changes to '\
376 'run-bisect-perf-regression.cfg for syntax errors.'
377 print
378 return 1
176 379
177 380
178 if __name__ == '__main__': 381 if __name__ == '__main__':
179 sys.exit(main()) 382 sys.exit(main())
OLDNEW
« no previous file with comments | « tools/bisect_utils.py ('k') | tools/run-perf-test.cfg » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698