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

Side by Side Diff: tools/perf/core/trybot_command.py

Issue 2287993004: Use git cl try --properties option to send test arguments instead of run-perf-test.cfg (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: . Created 4 years, 3 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 | « no previous file | tools/perf/core/trybot_command_unittest.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright 2015 The Chromium Authors. All rights reserved. 1 # Copyright 2015 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 import argparse 5 import argparse
6 import json
7 import logging
6 import os 8 import os
7 import logging
8 import platform 9 import platform
9 import re 10 import re
10 import subprocess 11 import subprocess
11 import urllib2 12 import urllib2
12 import json 13
13 14
14 from core import path_util 15 from core import path_util
15 16
16 from telemetry import benchmark 17 from telemetry import benchmark
17 from telemetry import decorators 18 from telemetry import decorators
18 from telemetry.core import discover 19 from telemetry.core import discover
19 from telemetry.util import command_line 20 from telemetry.util import command_line
20 from telemetry.util import matching 21 from telemetry.util import matching
21 22
22 23
23 CHROMIUM_CONFIG_FILENAME = 'tools/run-perf-test.cfg'
24 BLINK_CONFIG_FILENAME = 'Tools/run-perf-test.cfg'
25 SUCCESS, NO_CHANGES, ERROR = range(3)
26 # Unsupported Perf bisect bots. 24 # Unsupported Perf bisect bots.
27 EXCLUDED_BOTS = { 25 EXCLUDED_BOTS = {
28 'win_xp_perf_bisect', # Goma issues: crbug.com/330900 26 'win_xp_perf_bisect', # Goma issues: crbug.com/330900
29 'win_perf_bisect_builder', 27 'win_perf_bisect_builder',
30 'win64_nv_tester', 28 'win64_nv_tester',
31 'winx64_bisect_builder', 29 'winx64_bisect_builder',
32 'linux_perf_bisect_builder', 30 'linux_perf_bisect_builder',
33 'mac_perf_bisect_builder', 31 'mac_perf_bisect_builder',
34 'android_perf_bisect_builder', 32 'android_perf_bisect_builder',
35 'android_arm64_perf_bisect_builder', 33 'android_arm64_perf_bisect_builder',
(...skipping 14 matching lines...) Expand all
50 48
51 INCLUDE_BOTS = [ 49 INCLUDE_BOTS = [
52 'all', 50 'all',
53 'all-win', 51 'all-win',
54 'all-mac', 52 'all-mac',
55 'all-linux', 53 'all-linux',
56 'all-android' 54 'all-android'
57 ] 55 ]
58 56
59 # Default try bot to use incase builbot is unreachable. 57 # Default try bot to use incase builbot is unreachable.
60 DEFAULT_TRYBOTS = [ 58 DEFAULT_TRYBOTS = [
61 'linux_perf_bisect', 59 'linux_perf_bisect',
62 'mac_10_11_perf_bisect', 60 'mac_10_11_perf_bisect',
63 'winx64_10_perf_bisect', 61 'winx64_10_perf_bisect',
64 'android_s5_perf_bisect', 62 'android_s5_perf_bisect',
65 ] 63 ]
66 64
67 assert not set(DEFAULT_TRYBOTS) & set(EXCLUDED_BOTS), ( 'A trybot cannot ' 65 CHROMIUM_SRC_PATH = path_util.GetChromiumSrcDir()
68 'present in both Default as well as Excluded bots lists.') 66
67 assert not set(DEFAULT_TRYBOTS) & set(EXCLUDED_BOTS), (
68 'A trybot cannot present in both Default as well as Excluded bots lists.')
69
69 70
70 class TrybotError(Exception): 71 class TrybotError(Exception):
71 72
72 def __str__(self): 73 def __str__(self):
73 return '%s\nError running tryjob.' % self.args[0] 74 return '(ERROR) Perf Try Job: %s' % self.args[0]
74 75
75 76
76 def _GetTrybotList(builders): 77 def _GetTrybotList(builders):
77 builders = ['%s' % bot.replace('_perf_bisect', '').replace('_', '-') 78 builders = ['%s' % bot.replace('_perf_bisect', '').replace('_', '-')
78 for bot in builders] 79 for bot in builders]
79 builders.extend(INCLUDE_BOTS) 80 builders.extend(INCLUDE_BOTS)
80 return sorted(builders) 81 return sorted(builders)
81 82
82 83
83 def _GetBotPlatformFromTrybotName(trybot_name): 84 def _GetBotPlatformFromTrybotName(trybot_name):
84 os_names = ['linux', 'android', 'mac', 'win'] 85 os_names = ['linux', 'android', 'mac', 'win']
85 try: 86 try:
86 return next(b for b in os_names if b in trybot_name) 87 return next(b for b in os_names if b in trybot_name)
87 except StopIteration: 88 except StopIteration:
88 raise TrybotError('Trybot "%s" unsupported for tryjobs.' % trybot_name) 89 raise TrybotError('Trybot "%s" unsupported for tryjobs.' % trybot_name)
89 90
90 91
91 def _GetBuilderNames(trybot_name, builders): 92 def _GetBuilderNames(trybot_name, builders):
92 """ Return platform and its available bot name as dictionary.""" 93 """Return platform and its available bot name as dictionary."""
93 os_names = ['linux', 'android', 'mac', 'win'] 94 os_names = ['linux', 'android', 'mac', 'win']
94 if 'all' not in trybot_name: 95 if 'all' not in trybot_name:
95 bot = ['%s_perf_bisect' % trybot_name.replace('-', '_')] 96 bot = ['%s_perf_bisect' % trybot_name.replace('-', '_')]
96 bot_platform = _GetBotPlatformFromTrybotName(trybot_name) 97 bot_platform = _GetBotPlatformFromTrybotName(trybot_name)
97 if 'x64' in trybot_name: 98 if 'x64' in trybot_name:
98 bot_platform += '-x64' 99 bot_platform += '-x64'
99 return {bot_platform: bot} 100 return {bot_platform: bot}
100 101
101 platform_and_bots = {} 102 platform_and_bots = {}
102 for os_name in os_names: 103 for os_name in os_names:
(...skipping 15 matching lines...) Expand all
118 if 'all-mac' in trybot_name: 119 if 'all-mac' in trybot_name:
119 return {'mac': platform_and_bots['mac']} 120 return {'mac': platform_and_bots['mac']}
120 if 'all-android' in trybot_name: 121 if 'all-android' in trybot_name:
121 return {'android': platform_and_bots['android']} 122 return {'android': platform_and_bots['android']}
122 if 'all-linux' in trybot_name: 123 if 'all-linux' in trybot_name:
123 return {'linux': platform_and_bots['linux']} 124 return {'linux': platform_and_bots['linux']}
124 125
125 return platform_and_bots 126 return platform_and_bots
126 127
127 128
128 def _RunProcess(cmd): 129 _GIT_CMD = 'git'
129 logging.debug('Running process: "%s"', ' '.join(cmd))
130 proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
131 out, err = proc.communicate()
132 returncode = proc.poll()
133 return (returncode, out, err)
134 130
135 131
136 _GIT_CMD = 'git'
137 if platform.system() == 'Windows': 132 if platform.system() == 'Windows':
138 # On windows, the git command is installed as 'git.bat' 133 # On windows, the git command is installed as 'git.bat'
139 _GIT_CMD = 'git.bat' 134 _GIT_CMD = 'git.bat'
140 135
141 136
137 def RunGit(cmd, msg_on_error='', ignore_return_code=False):
138 """Runs the git command with the given arguments.
139
140 Args:
141 cmd: git command arguments.
142 msg_on_error: Message to be displayed on git command error.
143 ignore_return_code: Ignores the return code for git command.
144
145 Returns:
146 The output of the git command as string.
147
148 Raises:
149 TrybotError: This exception is raised when git command fails.
150 """
151 proc = subprocess.Popen(
152 [_GIT_CMD] + cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
153 output, err = proc.communicate()
154 returncode = proc.poll()
155 if returncode:
156 if ignore_return_code:
157 return None
158 raise TrybotError('%s. \n%s' % (msg_on_error, err))
159
160 return output
161
162
142 class Trybot(command_line.ArgParseCommand): 163 class Trybot(command_line.ArgParseCommand):
143 """ Run telemetry perf benchmark on trybot """ 164 """Run telemetry perf benchmark on trybot."""
144 165
145 usage = 'botname benchmark_name [<benchmark run options>]' 166 usage = 'botname benchmark_name [<benchmark run options>]'
146 _builders = None 167 _builders = None
147 168
148 def __init__(self): 169 def __init__(self):
149 self._builder_names = None 170 self._builder_names = None
150 171
151 @classmethod 172 @classmethod
152 def _GetBuilderList(cls): 173 def _GetBuilderList(cls):
153 if not cls._builders: 174 if not cls._builders:
154 try: 175 try:
155 f = urllib2.urlopen( 176 f = urllib2.urlopen(
156 ('https://build.chromium.org/p/tryserver.chromium.perf/json/' 177 ('https://build.chromium.org/p/tryserver.chromium.perf/json/'
157 'builders'), 178 'builders'),
158 timeout=5) 179 timeout=5)
159 # In case of any kind of exception, allow tryjobs to use default trybots. 180 # In case of any kind of exception, allow tryjobs to use default trybots.
160 # Possible exception are ssl.SSLError, urllib2.URLError, 181 # Possible exception are ssl.SSLError, urllib2.URLError,
161 # socket.timeout, socket.error. 182 # socket.timeout, socket.error.
162 except Exception: 183 except Exception: # pylint: disable=broad-except
163 # Incase of any exception return default trybots. 184 # Incase of any exception return default trybots.
164 print ('WARNING: Unable to reach builbot to retrieve trybot ' 185 print ('WARNING: Unable to reach builbot to retrieve trybot '
165 'information, tryjob will use default trybots.') 186 'information, tryjob will use default trybots.')
166 cls._builders = DEFAULT_TRYBOTS 187 cls._builders = DEFAULT_TRYBOTS
167 else: 188 else:
168 builders = json.loads(f.read()).keys() 189 builders = json.loads(f.read()).keys()
169 # Exclude unsupported bots like win xp and some dummy bots. 190 # Exclude unsupported bots like win xp and some dummy bots.
170 cls._builders = [bot for bot in builders if bot not in EXCLUDED_BOTS] 191 cls._builders = [bot for bot in builders if bot not in EXCLUDED_BOTS]
171 192
172 return cls._builders 193 return cls._builders
173 194
174 def _InitializeBuilderNames(self, trybot): 195 def _InitializeBuilderNames(self, trybot):
175 self._builder_names = _GetBuilderNames(trybot, self._GetBuilderList()) 196 self._builder_names = _GetBuilderNames(trybot, self._GetBuilderList())
176 197
177 @classmethod 198 @classmethod
178 def CreateParser(cls): 199 def CreateParser(cls):
179 parser = argparse.ArgumentParser( 200 parser = argparse.ArgumentParser(
180 ('Run telemetry benchmarks on trybot. You can add all the benchmark ' 201 ('Run telemetry benchmarks on trybot. You can add all the benchmark '
181 'options available except the --browser option'), 202 'options available except the --browser option'),
182 formatter_class=argparse.RawTextHelpFormatter) 203 formatter_class=argparse.RawTextHelpFormatter)
183 return parser 204 return parser
184 205
185 @classmethod 206 @classmethod
186 def ProcessCommandLineArgs(cls, parser, options, extra_args, environment): 207 def ProcessCommandLineArgs(cls, parser, options, extra_args, environment):
187 del environment # unused 208 del environment # unused
188 for arg in extra_args: 209 for arg in extra_args:
189 if arg == '--browser' or arg.startswith('--browser='): 210 if arg == '--browser' or arg.startswith('--browser='):
190 parser.error('--browser=... is not allowed when running trybot.') 211 parser.error('--browser=... is not allowed when running trybot.')
191 all_benchmarks = discover.DiscoverClasses( 212 all_benchmarks = discover.DiscoverClasses(
192 start_dir=path_util.GetPerfBenchmarksDir(), 213 start_dir=path_util.GetPerfBenchmarksDir(),
193 top_level_dir=path_util.GetPerfDir(), 214 top_level_dir=path_util.GetPerfDir(),
194 base_class=benchmark.Benchmark).values() 215 base_class=benchmark.Benchmark).values()
195 all_benchmark_names = [b.Name() for b in all_benchmarks] 216 all_benchmark_names = [b.Name() for b in all_benchmarks]
196 all_benchmarks_by_names = {b.Name(): b for b in all_benchmarks} 217 all_benchmarks_by_names = {b.Name(): b for b in all_benchmarks}
197 benchmark_class = all_benchmarks_by_names.get(options.benchmark_name, None) 218 benchmark_class = all_benchmarks_by_names.get(options.benchmark_name, None)
198 if not benchmark_class: 219 if not benchmark_class:
199 possible_benchmark_names = matching.GetMostLikelyMatchedObject( 220 possible_benchmark_names = matching.GetMostLikelyMatchedObject(
200 all_benchmark_names, options.benchmark_name) 221 all_benchmark_names, options.benchmark_name)
201 parser.error( 222 parser.error(
202 'No benchmark named "%s". Do you mean any of those benchmarks ' 223 'No benchmark named "%s". Do you mean any of those benchmarks '
203 'below?\n%s' % 224 'below?\n%s' % (
204 (options.benchmark_name, '\n'.join(possible_benchmark_names))) 225 options.benchmark_name, '\n'.join(possible_benchmark_names)))
205 is_benchmark_disabled, reason = cls.IsBenchmarkDisabledOnTrybotPlatform( 226 is_benchmark_disabled, reason = cls.IsBenchmarkDisabledOnTrybotPlatform(
206 benchmark_class, options.trybot) 227 benchmark_class, options.trybot)
207 also_run_disabled_option = '--also-run-disabled-tests' 228 also_run_disabled_option = '--also-run-disabled-tests'
208 if is_benchmark_disabled and also_run_disabled_option not in extra_args: 229 if is_benchmark_disabled and also_run_disabled_option not in extra_args:
209 parser.error('%s To run the benchmark on trybot anyway, add ' 230 parser.error('%s To run the benchmark on trybot anyway, add '
210 '%s option.' % (reason, also_run_disabled_option)) 231 '%s option.' % (reason, also_run_disabled_option))
211 232
212 @classmethod 233 @classmethod
213 def IsBenchmarkDisabledOnTrybotPlatform(cls, benchmark_class, trybot_name): 234 def IsBenchmarkDisabledOnTrybotPlatform(cls, benchmark_class, trybot_name):
214 """ Return whether benchmark will be disabled on trybot platform. 235 """Return whether benchmark will be disabled on trybot platform.
215 236
216 Note that we cannot tell with certainty whether the benchmark will be 237 Note that we cannot tell with certainty whether the benchmark will be
217 disabled on the trybot platform since the disable logic in ShouldDisable() 238 disabled on the trybot platform since the disable logic in ShouldDisable()
218 can be very dynamic and can only be verified on the trybot server platform. 239 can be very dynamic and can only be verified on the trybot server platform.
219 240
220 We are biased on the side of enabling the benchmark, and attempt to 241 We are biased on the side of enabling the benchmark, and attempt to
221 early discover whether the benchmark will be disabled as our best. 242 early discover whether the benchmark will be disabled as our best.
222 243
223 It should never be the case that the benchmark will be enabled on the test 244 It should never be the case that the benchmark will be enabled on the test
224 platform but this method returns True. 245 platform but this method returns True.
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
275 def Run(self, options, extra_args=None): 296 def Run(self, options, extra_args=None):
276 """Sends a tryjob to a perf trybot. 297 """Sends a tryjob to a perf trybot.
277 298
278 This creates a branch, telemetry-tryjob, switches to that branch, edits 299 This creates a branch, telemetry-tryjob, switches to that branch, edits
279 the bisect config, commits it, uploads the CL to rietveld, and runs a 300 the bisect config, commits it, uploads the CL to rietveld, and runs a
280 tryjob on the given bot. 301 tryjob on the given bot.
281 """ 302 """
282 if extra_args is None: 303 if extra_args is None:
283 extra_args = [] 304 extra_args = []
284 self._InitializeBuilderNames(options.trybot) 305 self._InitializeBuilderNames(options.trybot)
285 306 try:
286 arguments = [options.benchmark_name] + extra_args 307 self._AttemptTryjob(CHROMIUM_SRC_PATH, options, extra_args)
287 308 except TrybotError, error:
288 # First check if there are chromium changes to upload. 309 print error
289 status = self._AttemptTryjob(CHROMIUM_CONFIG_FILENAME, arguments) 310 return 1
290 if status not in [SUCCESS, ERROR]:
291 # If we got here, there are no chromium changes to upload. Try blink.
292 os.chdir('third_party/WebKit/')
293 status = self._AttemptTryjob(BLINK_CONFIG_FILENAME, arguments)
294 os.chdir('../..')
295 if status not in [SUCCESS, ERROR]:
296 logging.error('No local changes found in chromium or blink trees. '
297 'browser=%s argument sends local changes to the '
298 'perf trybot(s): %s.', options.trybot,
299 self._builder_names.values())
300 return 1
301 return 0 311 return 0
302 312
303 def _UpdateConfigAndRunTryjob(self, bot_platform, cfg_file_path, arguments):
304 """Updates perf config file, uploads changes and excutes perf try job.
305
306 Args:
307 bot_platform: Name of the platform to be generated.
308 cfg_file_path: Perf config file path.
309
310 Returns:
311 (result, msg) where result is one of:
312 SUCCESS if a tryjob was sent
313 NO_CHANGES if there was nothing to try,
314 ERROR if a tryjob was attempted but an error encountered
315 and msg is an error message if an error was encountered, or rietveld
316 url if success, otherwise throws TrybotError exception.
317 """
318 config = self._GetPerfConfig(bot_platform, arguments)
319 config_to_write = 'config = %s' % json.dumps(
320 config, sort_keys=True, indent=2, separators=(',', ': '))
321
322 try:
323 with open(cfg_file_path, 'r') as config_file:
324 if config_to_write == config_file.read():
325 return NO_CHANGES, ''
326 except IOError:
327 msg = 'Cannot find %s. Please run from src dir.' % cfg_file_path
328 return (ERROR, msg)
329
330 with open(cfg_file_path, 'w') as config_file:
331 config_file.write(config_to_write)
332 # Commit the config changes locally.
333 returncode, out, err = _RunProcess(
334 [_GIT_CMD, 'commit', '-a', '-m', 'bisect config: %s' % bot_platform])
335 if returncode:
336 raise TrybotError('Could not commit bisect config change for %s,'
337 ' error %s' % (bot_platform, err))
338 # Upload the CL to rietveld and run a try job.
339 returncode, out, err = _RunProcess([
340 _GIT_CMD, 'cl', 'upload', '-f', '--bypass-hooks', '-m',
341 'CL for perf tryjob on %s' % bot_platform
342 ])
343 if returncode:
344 raise TrybotError('Could not upload to rietveld for %s, error %s' %
345 (bot_platform, err))
346
347 match = re.search(r'https://codereview.chromium.org/[\d]+', out)
348 if not match:
349 raise TrybotError('Could not upload CL to rietveld for %s! Output %s' %
350 (bot_platform, out))
351 rietveld_url = match.group(0)
352 # Generate git try command for available bots.
353 git_try_command = [_GIT_CMD, 'cl', 'try', '-m', 'tryserver.chromium.perf']
354 for bot in self._builder_names[bot_platform]:
355 git_try_command.extend(['-b', bot])
356 returncode, out, err = _RunProcess(git_try_command)
357 if returncode:
358 raise TrybotError('Could not try CL for %s, error %s' %
359 (bot_platform, err))
360
361 return (SUCCESS, rietveld_url)
362
363 def _GetPerfConfig(self, bot_platform, arguments): 313 def _GetPerfConfig(self, bot_platform, arguments):
364 """Generates the perf config for try job. 314 """Generates the perf config for try job.
365 315
366 Args: 316 Args:
367 bot_platform: Name of the platform to be generated. 317 bot_platform: Name of the platform to be generated.
318 arguments: Command line arguments.
368 319
369 Returns: 320 Returns:
370 A dictionary with perf config parameters. 321 A dictionary with perf config parameters.
371 """ 322 """
372 # To make sure that we don't mutate the original args 323 # To make sure that we don't mutate the original args
373 arguments = arguments[:] 324 arguments = arguments[:]
374 325
375 # Always set verbose logging for later debugging 326 # Always set verbose logging for later debugging
376 if '-v' not in arguments and '--verbose' not in arguments: 327 if '-v' not in arguments and '--verbose' not in arguments:
377 arguments.append('--verbose') 328 arguments.append('--verbose')
378 329
379 # Generate the command line for the perf trybots 330 # Generate the command line for the perf trybots
380 target_arch = 'ia32' 331 target_arch = 'ia32'
381 if any(arg == '--chrome-root' or arg.startswith('--chrome-root=') for arg 332 if any(arg == '--chrome-root' or arg.startswith('--chrome-root=') for arg
382 in arguments): 333 in arguments):
383 raise ValueError( 334 raise ValueError(
384 'Trybot does not suport --chrome-root option set directly ' 335 'Trybot does not suport --chrome-root option set directly '
385 'through command line since it may contain references to your local ' 336 'through command line since it may contain references to your local '
386 'directory') 337 'directory')
387 if bot_platform in ['win', 'win-x64']:
388 arguments.insert(0, 'python tools\\perf\\run_benchmark')
389 else:
390 arguments.insert(0, './tools/perf/run_benchmark')
391 338
339 arguments.insert(0, 'src/tools/perf/run_benchmark')
392 if bot_platform == 'android': 340 if bot_platform == 'android':
393 arguments.insert(1, '--browser=android-chromium') 341 arguments.insert(1, '--browser=android-chromium')
394 elif any('x64' in bot for bot in self._builder_names[bot_platform]): 342 elif any('x64' in bot for bot in self._builder_names[bot_platform]):
395 arguments.insert(1, '--browser=release_x64') 343 arguments.insert(1, '--browser=release_x64')
396 target_arch = 'x64' 344 target_arch = 'x64'
397 else: 345 else:
346
398 arguments.insert(1, '--browser=release') 347 arguments.insert(1, '--browser=release')
399 348
400 command = ' '.join(arguments) 349 command = ' '.join(arguments)
401 350
402 return { 351 return {
403 'command': command, 352 'command': command,
404 'repeat_count': '1', 353 'repeat_count': '1',
405 'max_time_minutes': '120', 354 'max_time_minutes': '120',
406 'truncate_percent': '0', 355 'truncate_percent': '0',
407 'target_arch': target_arch, 356 'target_arch': target_arch,
408 } 357 }
409 358
410 def _AttemptTryjob(self, cfg_file_path, arguments): 359 def _GetRepoAndBranchName(self, repo_path):
411 """Attempts to run a tryjob from the current directory. 360 """Gets the repository name and working branch name.
412
413 This is run once for chromium, and if it returns NO_CHANGES, once for blink.
414 361
415 Args: 362 Args:
416 cfg_file_path: Path to the config file for the try job. 363 repo_path: Path to the repository.
417 364
418 Returns: 365 Returns:
419 Returns SUCCESS if a tryjob was sent, NO_CHANGES if there was nothing to 366 Repository name and branch name as tuple.
420 try, ERROR if a tryjob was attempted but an error encountered. 367
368 Raises:
369 TrybotError: This exception is raised for the following cases:
370 1. Try job is for non-git repository or in invalid branch.
371 2. Un-committed changes in the current branch.
372 3. No local commits in the current branch.
421 """ 373 """
422 source_repo = 'chromium' 374 # If command runs successfully, then the output will be repo root path.
423 if cfg_file_path == BLINK_CONFIG_FILENAME: 375 # and current branch name.
424 source_repo = 'blink' 376 output = RunGit(['rev-parse', '--abbrev-ref', '--show-toplevel', 'HEAD'],
377 ('%s is not a git repository, must be in a git repository '
378 'to send changes to trybots' % os.getcwd()))
425 379
426 # TODO(prasadv): This method is quite long, we should consider refactor 380 repo_info = output.split()
427 # this by extracting to helper methods. 381 # Assuming the base directory name is same as repo project name set in
428 returncode, original_branchname, err = _RunProcess( 382 # codereviews.settings file.
429 [_GIT_CMD, 'rev-parse', '--abbrev-ref', 'HEAD']) 383 repo_name = os.path.basename(repo_info[0]).strip()
430 if returncode: 384 branch_name = repo_info[1].strip()
431 msg = 'Must be in a git repository to send changes to trybots.'
432 if err:
433 msg += '\nGit error: %s' % err
434 logging.error(msg)
435 return ERROR
436 385
437 original_branchname = original_branchname.strip() 386 if branch_name == 'HEAD':
387 raise TrybotError('Not on a valid branch, looks like branch '
388 'is dettached. [branch:%s]' % branch_name)
438 389
439 # Check if the tree is dirty: make sure the index is up to date and then 390 # Check if the tree is dirty: make sure the index is up to date and then
440 # run diff-index 391 # run diff-index
441 _RunProcess([_GIT_CMD, 'update-index', '--refresh', '-q']) 392 RunGit(['update-index', '--refresh', '-q'], ignore_return_code=True)
442 returncode, out, err = _RunProcess([_GIT_CMD, 'diff-index', 'HEAD']) 393 output = RunGit(['diff-index', 'HEAD'])
443 if out: 394 if output:
444 logging.error( 395 raise TrybotError(
445 'Cannot send a try job with a dirty tree. Commit locally first.') 396 'Cannot send a try job with a dirty tree. Please commit '
446 return ERROR 397 'your changes locally first in %s repository.' % repo_path)
447 398
448 # Make sure the tree does have local commits. 399 # Make sure the tree does have local commits.
449 returncode, out, err = _RunProcess( 400 output = RunGit(['footers', 'HEAD'])
450 [_GIT_CMD, 'log', 'origin/master..HEAD']) 401 if output:
451 if not out: 402 raise TrybotError('No local changes found in %s repository.' % repo_path)
452 return NO_CHANGES
453 403
454 # Create/check out the telemetry-tryjob branch, and edit the configs 404 return (repo_name, branch_name)
455 # for the tryjob there. 405
456 returncode, out, err = _RunProcess( 406 def _AttemptTryjob(self, repo_path, options, extra_args):
457 [_GIT_CMD, 'checkout', '-b', 'telemetry-tryjob']) 407 """Attempts to run a tryjob from a repo directory.
458 if returncode: 408
459 logging.error('Error creating branch telemetry-tryjob. ' 409 Args:
460 'Please delete it if it exists.\n%s', err) 410 repo_path: Path to the repository.
461 return ERROR 411 options: Command line arguments to run benchmark.
462 try: 412 extra_args: Extra arugments to run benchmark.
463 returncode, out, err = _RunProcess( 413 """
464 [_GIT_CMD, 'branch', '--set-upstream-to', 'origin/master']) 414 repo_name, branch_name = self._GetRepoAndBranchName(repo_path)
465 if returncode: 415
466 logging.error('Error in git branch --set-upstream-to: %s', err) 416 arguments = [options.benchmark_name] + extra_args
467 return ERROR 417
468 for bot_platform in self._builder_names: 418 rietveld_url = self._UploadPatchToRietveld(repo_name, options)
469 if not self._builder_names[bot_platform]: 419 print ('\nUploaded try job to rietveld.\nview progress here %s.'
470 logging.warning('No builder is found for %s', bot_platform) 420 '\n\tRepo Name: %s\n\tPath: %s\n\tBranch: %s' % (
471 continue 421 rietveld_url, repo_name, repo_path, branch_name))
472 try: 422
473 results, output = self._UpdateConfigAndRunTryjob( 423 for bot_platform in self._builder_names:
474 bot_platform, cfg_file_path, arguments) 424 if not self._builder_names[bot_platform]:
475 if results == ERROR: 425 logging.warning('No builder is found for %s', bot_platform)
476 logging.error(output) 426 continue
477 return ERROR 427 try:
478 elif results == NO_CHANGES: 428 self._RunTryJob(bot_platform, arguments)
479 print ('Skip the try job run on %s because it has been tried in ' 429 except TrybotError, err:
480 'previous try job run. ' % bot_platform) 430 print err
481 else: 431
482 print ('Uploaded %s try job to rietveld for %s platform. ' 432 def _UploadPatchToRietveld(self, repo_name, options):
483 'View progress at %s' % (source_repo, bot_platform, output)) 433 """Uploads the patch to rietveld and returns rietveld URL."""
484 except TrybotError, err: 434 output = RunGit(['cl', 'upload', '-f', '--bypass-hooks', '-m',
485 print err 435 ('CL for %s perf tryjob to run %s benchmark '
486 logging.error(err) 436 'on %s platform(s)' % (
487 finally: 437 repo_name, options.benchmark_name, options.trybot))],
488 # Checkout original branch and delete telemetry-tryjob branch. 438 'Could not upload to rietveld for %s' % repo_name)
489 # TODO(prasadv): This finally block could be extracted out to be a 439
490 # separate function called _CleanupBranch. 440 match = re.search(r'https://codereview.chromium.org/[\d]+', output)
491 returncode, out, err = _RunProcess( 441 if not match:
492 [_GIT_CMD, 'checkout', original_branchname]) 442 raise TrybotError('Could not upload CL to rietveld for %s! Output %s' %
493 if returncode: 443 (repo_name, output))
494 logging.error('Could not check out %s. Please check it out and ' 444 return match.group(0)
495 'manually delete the telemetry-tryjob branch. ' 445
496 ': %s', original_branchname, err) 446 def _RunTryJob(self, bot_platform, arguments):
497 return ERROR # pylint: disable=lost-exception 447 """Executes perf try job with benchmark test properties.
498 logging.info('Checked out original branch: %s', original_branchname) 448
499 returncode, out, err = _RunProcess( 449 Args:
500 [_GIT_CMD, 'branch', '-D', 'telemetry-tryjob']) 450 bot_platform: Name of the platform to be generated.
501 if returncode: 451 arguments: Command line arguments.
502 logging.error('Could not delete telemetry-tryjob branch. ' 452
503 'Please delete it manually: %s', err) 453 Raises:
504 return ERROR # pylint: disable=lost-exception 454 TrybotError: When trybot fails to upload CL or run git try.
505 logging.info('Deleted temp branch: telemetry-tryjob') 455 """
506 return SUCCESS 456 config = self._GetPerfConfig(bot_platform, arguments)
457
458 # Generate git try command for available bots.
459 git_try_command = ['cl', 'try', '-m', 'tryserver.chromium.perf']
460
461 # Add Perf Test config to git try --properties arg.
462 git_try_command.extend(['-p', 'perf_try_config=%s' % json.dumps(config)])
463
464 for bot in self._builder_names[bot_platform]:
465 git_try_command.extend(['-b', bot])
466
467 RunGit(git_try_command, 'Could not try CL for %s' % bot_platform)
468 print 'Perf Try job sent to rietveld for %s platform.' % bot_platform
OLDNEW
« no previous file with comments | « no previous file | tools/perf/core/trybot_command_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698