| Index: tools/telemetry/telemetry/core/backends/remote/trybot_browser_finder.py
|
| diff --git a/tools/telemetry/telemetry/core/backends/remote/trybot_browser_finder.py b/tools/telemetry/telemetry/core/backends/remote/trybot_browser_finder.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..dba968f3630356b2434a8481c59de04bba0f3512
|
| --- /dev/null
|
| +++ b/tools/telemetry/telemetry/core/backends/remote/trybot_browser_finder.py
|
| @@ -0,0 +1,210 @@
|
| +# Copyright 2014 The Chromium Authors. All rights reserved.
|
| +# Use of this source code is governed by a BSD-style license that can be
|
| +# found in the LICENSE file.
|
| +
|
| +"""Finds perf trybots that can run telemetry tests."""
|
| +
|
| +import json
|
| +import logging
|
| +import re
|
| +import subprocess
|
| +import sys
|
| +import urllib2
|
| +
|
| +from telemetry import decorators
|
| +from telemetry.core import platform
|
| +from telemetry.core import possible_browser
|
| +
|
| +# TODO(sullivan): Check for blink changes
|
| +CONFIG_FILENAME = 'tools/run-perf-test.cfg'
|
| +
|
| +
|
| +class PossibleTrybotBrowser(possible_browser.PossibleBrowser):
|
| + """A script that sends a job to a trybot."""
|
| +
|
| + def __init__(self, browser_type, finder_options):
|
| + target_os = browser_type.split('-')[1]
|
| + self._buildername = '%s_perf_bisect' % browser_type.replace(
|
| + 'trybot-', '').replace('-', '_')
|
| + super(PossibleTrybotBrowser, self).__init__(browser_type, target_os,
|
| + finder_options, True)
|
| +
|
| + def Create(self):
|
| + raise NotImplementedError()
|
| +
|
| + def SupportsOptions(self, finder_options):
|
| + if (finder_options.android_device or
|
| + finder_options.chrome_root or
|
| + finder_options.cros_remote or
|
| + finder_options.extensions_to_load or
|
| + finder_options.interactive or
|
| + finder_options.profile_dir):
|
| + return False
|
| + return True
|
| +
|
| + def IsRemote(self):
|
| + return True
|
| +
|
| + def _RunProcess(self, cmd):
|
| + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
| + out, err = proc.communicate()
|
| + returncode = proc.poll()
|
| + return (returncode, out, err)
|
| +
|
| + def RunRemote(self):
|
| + """Sends a tryjob to a perf trybot.
|
| +
|
| + This creates a branch, telemetry-tryjob, switches to that branch, edits
|
| + the bisect config, commits it, uploads the CL to rietveld, and runs a
|
| + tryjob on the given bot.
|
| + """
|
| + returncode, original_branchname, err = self._RunProcess(
|
| + ['git', 'rev-parse', '--abbrev-ref', 'HEAD'])
|
| + if returncode:
|
| + logging.error('Must be in a git repository to send changes to trybots.')
|
| + if err:
|
| + logging.error('Git error: %s', err)
|
| + return
|
| + original_branchname = original_branchname.strip()
|
| +
|
| + # Check if the tree is dirty: make sure the index is up to date and then
|
| + # run diff-index
|
| + self._RunProcess(['git', 'update-index', '--refresh', '-q'])
|
| + returncode, out, err = self._RunProcess(['git', 'diff-index', 'HEAD'])
|
| + if out:
|
| + logging.error(
|
| + 'Cannot send a try job with a dirty tree. Commit locally first.')
|
| + return
|
| +
|
| + # Make sure the tree does have local commits.
|
| + returncode, out, err = self._RunProcess(
|
| + ['git', 'log', 'origin/master..HEAD'])
|
| + if not out:
|
| + logging.error('No local changes on branch %s. browser=%s argument sends '
|
| + 'local changes to the %s perf trybot.', original_branchname,
|
| + self._browser_type, self._buildername)
|
| + return
|
| +
|
| + # Create/check out the telemetry-tryjob branch, and edit the configs
|
| + # for the tryjob there.
|
| + returncode, out, err = self._RunProcess(
|
| + ['git', 'checkout', '-b', 'telemetry-tryjob'])
|
| + if returncode:
|
| + logging.error('Error creating branch telemetry-tryjob. '
|
| + 'Please delete it if it exists.')
|
| + logging.error(err)
|
| + return
|
| +
|
| + # Generate the command line for the perf trybots
|
| + arguments = sys.argv
|
| + if self._target_os == 'win':
|
| + arguments[0] = 'python tools\\perf\\run_measurement'
|
| + else:
|
| + arguments[0] = './tools/perf/run_measurement'
|
| + for index, arg in enumerate(arguments):
|
| + if arg.startswith('--browser='):
|
| + if self._target_os == 'android':
|
| + arguments[index] = '--browser=android-chrome-shell'
|
| + else:
|
| + arguments[index] = '--browser=release'
|
| + command = ' '.join(arguments)
|
| +
|
| + # Add the correct command to the config file and commit it.
|
| + config = {
|
| + 'command': command,
|
| + 'repeat_count': '1',
|
| + 'max_time_minutes': '120',
|
| + 'truncate_percent': '0',
|
| + }
|
| + try:
|
| + config_file = open(CONFIG_FILENAME, 'w')
|
| + except IOError:
|
| + logging.error('Cannot find %s. Please run from src dir.', CONFIG_FILENAME)
|
| + return
|
| + config_file.write('config = %s' % json.dumps(
|
| + config, sort_keys=True, indent=2, separators=(',', ': ')))
|
| + config_file.close()
|
| + returncode, out, err = self._RunProcess(
|
| + ['git', 'commit', '-a', '-m', 'bisect config'])
|
| + if returncode:
|
| + logging.error('Could not commit bisect config change, error %s', err)
|
| + return
|
| +
|
| + # Upload the CL to rietveld and run a try job.
|
| + returncode, out, err = self._RunProcess([
|
| + 'git', 'cl', 'upload', '-f', '--bypass-hooks', '-m',
|
| + 'CL for perf tryjob'
|
| + ])
|
| + if returncode:
|
| + logging.error('Could upload to reitveld, error %s', err)
|
| + return
|
| + match = re.search(r'https://codereview.chromium.org/[\d]+', out)
|
| + if not match:
|
| + logging.error('Could not upload CL to reitveld! Output %s', out)
|
| + return
|
| + print 'Uploaded try job to reitveld. View progress at %s' % match.group(0)
|
| + returncode, out, err = self._RunProcess([
|
| + 'git', 'cl', 'try', '-m', 'tryserver.chromium.perf',
|
| + '-b', self._buildername])
|
| + if returncode:
|
| + logging.error('Could not try CL, error %s', err)
|
| + return
|
| +
|
| + # Checkout original branch and delete telemetry-tryjob branch.
|
| + returncode, out, err = self._RunProcess(
|
| + ['git', 'checkout', original_branchname])
|
| + if returncode:
|
| + logging.error(
|
| + ('Could not check out %s. Please check it out and manually '
|
| + 'delete the telemetry-tryjob branch. Error message: %s'),
|
| + original_branchname, err)
|
| + return
|
| + returncode, out, err = self._RunProcess(
|
| + ['git', 'branch', '-D', 'telemetry-tryjob'])
|
| + if returncode:
|
| + logging.error(('Could not delete telemetry-tryjob branch. '
|
| + 'Please delete it manually. Error %s'), err)
|
| + return
|
| +
|
| + def _InitPlatformIfNeeded(self):
|
| + if self._platform:
|
| + return
|
| +
|
| + self._platform = platform.GetHostPlatform()
|
| +
|
| + # pylint: disable=W0212
|
| + self._platform_backend = self._platform._platform_backend
|
| +
|
| +
|
| +def SelectDefaultBrowser(_):
|
| + return None
|
| +
|
| +
|
| +def CanFindAvailableBrowsers():
|
| + return True
|
| +
|
| +
|
| +@decorators.Cache
|
| +def _GetTrybotList():
|
| + f = urllib2.urlopen(
|
| + 'http://build.chromium.org/p/tryserver.chromium.perf/json')
|
| + builders = json.loads(f.read()).get('builders', {}).keys()
|
| + builders = ['trybot-%s' % b.replace('_perf_bisect', '').replace('_', '-')
|
| + for b in builders if not b.endswith('_perf_bisect_builder')]
|
| + return builders
|
| +
|
| +
|
| +def FindAllBrowserTypes(finder_options):
|
| + # Listing browsers requires an http request; only do this if the user is
|
| + # running with browser=list or a browser=trybot-* argument.
|
| + if (finder_options.browser_type and
|
| + (finder_options.browser_type == 'list' or
|
| + finder_options.browser_type.startswith('trybot'))):
|
| + return _GetTrybotList()
|
| + return []
|
| +
|
| +
|
| +def FindAllAvailableBrowsers(finder_options):
|
| + """Find all perf trybots on tryserver.chromium.perf."""
|
| + return [PossibleTrybotBrowser(b, finder_options) for b in
|
| + FindAllBrowserTypes(finder_options)]
|
|
|