OLD | NEW |
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 | 6 import json |
7 import logging | 7 import logging |
8 import os | 8 import os |
9 import platform | 9 import platform |
10 import re | 10 import re |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
56 | 56 |
57 # Default try bot to use incase builbot is unreachable. | 57 # Default try bot to use incase builbot is unreachable. |
58 DEFAULT_TRYBOTS = [ | 58 DEFAULT_TRYBOTS = [ |
59 'linux_perf_bisect', | 59 'linux_perf_bisect', |
60 'mac_10_11_perf_bisect', | 60 'mac_10_11_perf_bisect', |
61 'winx64_10_perf_bisect', | 61 'winx64_10_perf_bisect', |
62 'android_s5_perf_bisect', | 62 'android_s5_perf_bisect', |
63 ] | 63 ] |
64 | 64 |
65 CHROMIUM_SRC_PATH = path_util.GetChromiumSrcDir() | 65 CHROMIUM_SRC_PATH = path_util.GetChromiumSrcDir() |
| 66 # Mapping of repo to its root path and git remote URL. |
| 67 # Values for 'src' key in the map are related to path to the repo in the |
| 68 # DEPS file, These values are to used create the DEPS patch along with patch |
| 69 # that is being tried. |
| 70 REPO_INFO_MAP = { |
| 71 'src': { |
| 72 'src': 'src', |
| 73 'url': 'https://chromium.googlesource.com/chromium/src.git', |
| 74 }, |
| 75 'v8': { |
| 76 'src': 'src/v8', |
| 77 'url': 'https://chromium.googlesource.com/v8/v8.git', |
| 78 }, |
| 79 'skia': { |
| 80 'src': 'src/third_party/skia', |
| 81 'url': 'https://chromium.googlesource.com/skia.git', |
| 82 }, |
| 83 'angle': { |
| 84 'src': 'src/third_party/angle', |
| 85 'url': 'https://chromium.googlesource.com/angle/angle.git', |
| 86 }, |
| 87 'catapult': { |
| 88 'src': 'src/third_party/catapult', |
| 89 'url': ('https://chromium.googlesource.com/external/github.com/' |
| 90 'catapult-project/catapult.git') |
| 91 } |
| 92 } |
66 | 93 |
67 assert not set(DEFAULT_TRYBOTS) & set(EXCLUDED_BOTS), ( | 94 assert not set(DEFAULT_TRYBOTS) & set(EXCLUDED_BOTS), ( |
68 'A trybot cannot present in both Default as well as Excluded bots lists.') | 95 'A trybot cannot present in both Default as well as Excluded bots lists.') |
69 | 96 |
70 | 97 |
71 class TrybotError(Exception): | 98 class TrybotError(Exception): |
72 | 99 |
73 def __str__(self): | 100 def __str__(self): |
74 return '(ERROR) Perf Try Job: %s' % self.args[0] | 101 return '(ERROR) Perf Try Job: %s' % self.args[0] |
75 | 102 |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
150 """ | 177 """ |
151 proc = subprocess.Popen( | 178 proc = subprocess.Popen( |
152 [_GIT_CMD] + cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | 179 [_GIT_CMD] + cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
153 output, err = proc.communicate() | 180 output, err = proc.communicate() |
154 returncode = proc.poll() | 181 returncode = proc.poll() |
155 if returncode: | 182 if returncode: |
156 if ignore_return_code: | 183 if ignore_return_code: |
157 return None | 184 return None |
158 raise TrybotError('%s. \n%s' % (msg_on_error, err)) | 185 raise TrybotError('%s. \n%s' % (msg_on_error, err)) |
159 | 186 |
160 return output | 187 return output.strip() |
161 | 188 |
162 | 189 |
163 class Trybot(command_line.ArgParseCommand): | 190 class Trybot(command_line.ArgParseCommand): |
164 """Run telemetry perf benchmark on trybot.""" | 191 """Run telemetry perf benchmark on trybot.""" |
165 | 192 |
166 usage = 'botname benchmark_name [<benchmark run options>]' | 193 usage = 'botname benchmark_name [<benchmark run options>]' |
167 _builders = None | 194 _builders = None |
168 | 195 |
169 def __init__(self): | 196 def __init__(self): |
170 self._builder_names = None | 197 self._builder_names = None |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
285 parser.add_argument( | 312 parser.add_argument( |
286 'trybot', choices=available_bots, | 313 'trybot', choices=available_bots, |
287 help=('specify which bots to run telemetry benchmarks on. ' | 314 help=('specify which bots to run telemetry benchmarks on. ' |
288 ' Allowed values are:\n' + '\n'.join(available_bots)), | 315 ' Allowed values are:\n' + '\n'.join(available_bots)), |
289 metavar='<trybot name>') | 316 metavar='<trybot name>') |
290 parser.add_argument( | 317 parser.add_argument( |
291 'benchmark_name', type=str, | 318 'benchmark_name', type=str, |
292 help=('specify which benchmark to run. To see all available benchmarks,' | 319 help=('specify which benchmark to run. To see all available benchmarks,' |
293 ' run `run_benchmark list`'), | 320 ' run `run_benchmark list`'), |
294 metavar='<benchmark name>') | 321 metavar='<benchmark name>') |
| 322 parser.add_argument( |
| 323 '--repo_path', type=str, default=CHROMIUM_SRC_PATH, |
| 324 help=("""specify the repo path where the patch is created.' |
| 325 This argument should only be used if the changes are made outside chromium repo. |
| 326 E.g., |
| 327 1) Assume you are running run_benchmarks command from $HOME/cr/src/ direcory:' |
| 328 a) If your changes are in $HOME/cr/src/v8, then --repo_path=v8 or |
| 329 --repo-path=$HOME/cr/src/v8 |
| 330 b) If your changes are in $HOME/cr/src/third_party/catapult, then |
| 331 --repo_path=third_party/catapult or |
| 332 --repo_path = $HOME/cr/src/third_party/catapult' |
| 333 c) If your changes are not relative to src/ e.g. you created changes in some |
| 334 other direcotry say $HOME/mydir/v8/v8/, then the |
| 335 --repo_path=$HOME/mydir/v8/v8 |
| 336 2) Assume you are running run_benchmarks command not relatvie to src i.e., |
| 337 you are running from $HOME/mydir/ direcory:' |
| 338 a) If your changes are in $HOME/cr/src/v8, then --repo-path=$HOME/cr/src/v8 |
| 339 b) If your changes are in $HOME/cr/src/third_party/catapult, then |
| 340 --repo_path=$HOME/cr/src/third_party/catapult' |
| 341 c) If your changes are in $HOME/mydir/v8/v8/, then the |
| 342 --repo_path=$HOME/mydir/v8/v8 or --repo_path=v8/v8"""), |
| 343 metavar='<repo path>') |
| 344 parser.add_argument( |
| 345 '--deps_revision', type=str, default=None, |
| 346 help=('specify DEPS revision to modify DEPS entry in Chromium to a ' |
| 347 'certain pushed revision.\n' |
| 348 'This revision overrides value in DEPS on TOT Chromium for the ' |
| 349 'repo specified in --repo_path.\nIt is applied for both with and ' |
| 350 'wihout patch.'), |
| 351 metavar='<deps revision>') |
295 | 352 |
296 def Run(self, options, extra_args=None): | 353 def Run(self, options, extra_args=None): |
297 """Sends a tryjob to a perf trybot. | 354 """Sends a tryjob to a perf trybot. |
298 | 355 |
299 This creates a branch, telemetry-tryjob, switches to that branch, edits | 356 This creates a branch, telemetry-tryjob, switches to that branch, edits |
300 the bisect config, commits it, uploads the CL to rietveld, and runs a | 357 the bisect config, commits it, uploads the CL to rietveld, and runs a |
301 tryjob on the given bot. | 358 tryjob on the given bot. |
302 """ | 359 """ |
303 if extra_args is None: | 360 if extra_args is None: |
304 extra_args = [] | 361 extra_args = [] |
305 self._InitializeBuilderNames(options.trybot) | 362 self._InitializeBuilderNames(options.trybot) |
306 try: | 363 |
307 self._AttemptTryjob(CHROMIUM_SRC_PATH, options, extra_args) | 364 return self._AttemptTryjob(options, extra_args) |
308 except TrybotError, error: | |
309 print error | |
310 return 1 | |
311 return 0 | |
312 | 365 |
313 def _GetPerfConfig(self, bot_platform, arguments): | 366 def _GetPerfConfig(self, bot_platform, arguments): |
314 """Generates the perf config for try job. | 367 """Generates the perf config for try job. |
315 | 368 |
316 Args: | 369 Args: |
317 bot_platform: Name of the platform to be generated. | 370 bot_platform: Name of the platform to be generated. |
318 arguments: Command line arguments. | 371 arguments: Command line arguments. |
319 | 372 |
320 Returns: | 373 Returns: |
321 A dictionary with perf config parameters. | 374 A dictionary with perf config parameters. |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
396 'Cannot send a try job with a dirty tree. Please commit ' | 449 'Cannot send a try job with a dirty tree. Please commit ' |
397 'your changes locally first in %s repository.' % repo_path) | 450 'your changes locally first in %s repository.' % repo_path) |
398 | 451 |
399 # Make sure the tree does have local commits. | 452 # Make sure the tree does have local commits. |
400 output = RunGit(['footers', 'HEAD']) | 453 output = RunGit(['footers', 'HEAD']) |
401 if output: | 454 if output: |
402 raise TrybotError('No local changes found in %s repository.' % repo_path) | 455 raise TrybotError('No local changes found in %s repository.' % repo_path) |
403 | 456 |
404 return (repo_name, branch_name) | 457 return (repo_name, branch_name) |
405 | 458 |
406 def _AttemptTryjob(self, repo_path, options, extra_args): | 459 def _GetBaseGitHashForRepo(self, branch_name, git_url): |
| 460 """Gets the base revision for the repo on which local changes are made. |
| 461 |
| 462 Finds the upstream of the current branch that it is set to and gets |
| 463 the HEAD revision from upstream. This also checks if the remote URL on |
| 464 the upstream is supported by Perf Try job. |
| 465 |
| 466 Args: |
| 467 branch_name: Current working branch name. |
| 468 git_url: Remote URL of the repo. |
| 469 |
| 470 Returns: |
| 471 Git hash of the HEAD revision from the upstream branch. |
| 472 |
| 473 Raises: |
| 474 TrybotError: This exception is raised when a GIT command fails or if the |
| 475 remote URL of the repo found is not supported. |
| 476 """ |
| 477 # Check if there is any upstream branch associated with current working |
| 478 # branch, Once the upstream branch is found i.e., then validates the |
| 479 # remote URL and then returns the HEAD revision from the remote branch. |
| 480 while not self._IsRepoSupported(branch_name, git_url): |
| 481 branch_name = RunGit( |
| 482 ['rev-parse', '--abbrev-ref', '%s@{upstream}' % branch_name], |
| 483 'Failed to get upstream branch name.') |
| 484 |
| 485 return RunGit( |
| 486 ['rev-parse', '%s@{upstream}' % branch_name], |
| 487 'Failed to get base revision hash on upstream.') |
| 488 |
| 489 def _IsRepoSupported(self, current_branch, repo_git_url): |
| 490 cur_remote = RunGit( |
| 491 ['config', 'branch.%s.remote'% current_branch], |
| 492 'Failed to get branch.%s.remote from git config' % current_branch) |
| 493 cur_remote = cur_remote.strip() |
| 494 if cur_remote == '.': |
| 495 return False |
| 496 cur_remote_url = RunGit( |
| 497 ['config', 'remote.%s.url' % cur_remote], |
| 498 'Failed to get remote.%s.url from git config' % cur_remote) |
| 499 if cur_remote_url.lower() == repo_git_url: |
| 500 return True |
| 501 raise TrybotError('URL %s on remote %s is not recognized on branch.'% ( |
| 502 cur_remote_url, cur_remote)) |
| 503 |
| 504 def _AttemptTryjob(self, options, extra_args): |
407 """Attempts to run a tryjob from a repo directory. | 505 """Attempts to run a tryjob from a repo directory. |
408 | 506 |
409 Args: | 507 Args: |
410 repo_path: Path to the repository. | |
411 options: Command line arguments to run benchmark. | 508 options: Command line arguments to run benchmark. |
412 extra_args: Extra arugments to run benchmark. | 509 extra_args: Extra arugments to run benchmark. |
| 510 |
| 511 Returns: |
| 512 If successful returns 0, otherwise 1. |
413 """ | 513 """ |
414 repo_name, branch_name = self._GetRepoAndBranchName(repo_path) | 514 original_workdir = os.getcwd() |
| 515 repo_path = os.path.abspath(options.repo_path) |
| 516 try: |
| 517 # Check the existence of repo path. |
| 518 if not os.path.exists(repo_path): |
| 519 raise TrybotError('Repository path "%s" does not exist, please check ' |
| 520 'the value of <repo_path> argument.' % repo_path) |
| 521 # Change to the repo directory. |
| 522 os.chdir(repo_path) |
| 523 repo_name, branch_name = self._GetRepoAndBranchName(repo_path) |
415 | 524 |
416 arguments = [options.benchmark_name] + extra_args | 525 repo_info = REPO_INFO_MAP.get(repo_name, None) |
| 526 if not repo_info: |
| 527 raise TrybotError('Unsupported repository %s' % repo_name) |
417 | 528 |
418 rietveld_url = self._UploadPatchToRietveld(repo_name, options) | 529 deps_override = None |
419 print ('\nUploaded try job to rietveld.\nview progress here %s.' | 530 if repo_name != 'src': |
420 '\n\tRepo Name: %s\n\tPath: %s\n\tBranch: %s' % ( | 531 if not options.deps_revision: |
421 rietveld_url, repo_name, repo_path, branch_name)) | 532 options.deps_revision = self._GetBaseGitHashForRepo( |
| 533 branch_name, repo_info.get('url')) |
| 534 deps_override = {repo_info.get('src'): options.deps_revision} |
422 | 535 |
423 for bot_platform in self._builder_names: | 536 arguments = [options.benchmark_name] + extra_args |
424 if not self._builder_names[bot_platform]: | 537 |
425 logging.warning('No builder is found for %s', bot_platform) | 538 rietveld_url = self._UploadPatchToRietveld(repo_name, options) |
426 continue | 539 print ('\nUploaded try job to rietveld.\nview progress here %s.' |
427 try: | 540 '\n\tRepo Name: %s\n\tPath: %s\n\tBranch: %s' % ( |
428 self._RunTryJob(bot_platform, arguments) | 541 rietveld_url, repo_name, repo_path, branch_name)) |
429 except TrybotError, err: | 542 |
430 print err | 543 for bot_platform in self._builder_names: |
| 544 if not self._builder_names[bot_platform]: |
| 545 logging.warning('No builder is found for %s', bot_platform) |
| 546 continue |
| 547 try: |
| 548 self._RunTryJob(bot_platform, arguments, deps_override) |
| 549 # Even if git cl try throws TrybotError exception for any platform, |
| 550 # keep sending try jobs to other platforms. |
| 551 except TrybotError, err: |
| 552 print err |
| 553 except TrybotError, error: |
| 554 print error |
| 555 return 1 |
| 556 finally: |
| 557 # Restore to original working directory. |
| 558 os.chdir(original_workdir) |
| 559 return 0 |
431 | 560 |
432 def _UploadPatchToRietveld(self, repo_name, options): | 561 def _UploadPatchToRietveld(self, repo_name, options): |
433 """Uploads the patch to rietveld and returns rietveld URL.""" | 562 """Uploads the patch to rietveld and returns rietveld URL.""" |
434 output = RunGit(['cl', 'upload', '-f', '--bypass-hooks', '-m', | 563 output = RunGit(['cl', 'upload', '-f', '--bypass-hooks', '-m', |
435 ('CL for %s perf tryjob to run %s benchmark ' | 564 ('CL for %s perf tryjob to run %s benchmark ' |
436 'on %s platform(s)' % ( | 565 'on %s platform(s)' % ( |
437 repo_name, options.benchmark_name, options.trybot))], | 566 repo_name, options.benchmark_name, options.trybot))], |
438 'Could not upload to rietveld for %s' % repo_name) | 567 'Could not upload to rietveld for %s' % repo_name) |
439 | 568 |
440 match = re.search(r'https://codereview.chromium.org/[\d]+', output) | 569 match = re.search(r'https://codereview.chromium.org/[\d]+', output) |
441 if not match: | 570 if not match: |
442 raise TrybotError('Could not upload CL to rietveld for %s! Output %s' % | 571 raise TrybotError('Could not upload CL to rietveld for %s! Output %s' % |
443 (repo_name, output)) | 572 (repo_name, output)) |
444 return match.group(0) | 573 return match.group(0) |
445 | 574 |
446 def _RunTryJob(self, bot_platform, arguments): | 575 def _RunTryJob(self, bot_platform, arguments, deps_override): |
447 """Executes perf try job with benchmark test properties. | 576 """Executes perf try job with benchmark test properties. |
448 | 577 |
449 Args: | 578 Args: |
450 bot_platform: Name of the platform to be generated. | 579 bot_platform: Name of the platform to be generated. |
451 arguments: Command line arguments. | 580 arguments: Command line arguments. |
| 581 deps_override: DEPS revision if needs to be overridden. |
452 | 582 |
453 Raises: | 583 Raises: |
454 TrybotError: When trybot fails to upload CL or run git try. | 584 TrybotError: When trybot fails to upload CL or run git try. |
455 """ | 585 """ |
456 config = self._GetPerfConfig(bot_platform, arguments) | 586 config = self._GetPerfConfig(bot_platform, arguments) |
457 | 587 |
458 # Generate git try command for available bots. | 588 # Generate git try command for available bots. |
459 git_try_command = ['cl', 'try', '-m', 'tryserver.chromium.perf'] | 589 git_try_command = ['cl', 'try', '-m', 'tryserver.chromium.perf'] |
460 | 590 |
461 # Add Perf Test config to git try --properties arg. | 591 # Add Perf Test config to git try --properties arg. |
462 git_try_command.extend(['-p', 'perf_try_config=%s' % json.dumps(config)]) | 592 git_try_command.extend(['-p', 'perf_try_config=%s' % json.dumps(config)]) |
463 | 593 |
| 594 # Add deps overrides to git try --properties arg. |
| 595 if deps_override: |
| 596 git_try_command.extend([ |
| 597 '-p', 'deps_revision_overrides=%s' % json.dumps(deps_override)]) |
464 for bot in self._builder_names[bot_platform]: | 598 for bot in self._builder_names[bot_platform]: |
465 git_try_command.extend(['-b', bot]) | 599 git_try_command.extend(['-b', bot]) |
466 | 600 |
467 RunGit(git_try_command, 'Could not try CL for %s' % bot_platform) | 601 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 | 602 print 'Perf Try job sent to rietveld for %s platform.' % bot_platform |
OLD | NEW |