| #!/usr/bin/env python |
| # Copyright 2013 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. |
| |
| """Run Manual Test Bisect Tool |
| |
| An example usage: |
| tools/run-bisect-manual-test.py -g 201281 -b 201290 |
| |
| On Linux platform, follow the instructions in this document |
| https://chromium.googlesource.com/chromium/src/+/master/docs/linux_suid_sandbox_development.md |
| to setup the sandbox manually before running the script. Otherwise the script |
| fails to launch Chrome and exits with an error. |
| |
| This script serves a similar function to bisect-builds.py, except it uses |
| the bisect_perf_regression.py. This means that that it can obtain builds of |
| Chromium for revisions where builds aren't available in cloud storage. |
| """ |
| |
| import os |
| import subprocess |
| import sys |
| |
| CROS_BOARD_ENV = 'BISECT_CROS_BOARD' |
| CROS_IP_ENV = 'BISECT_CROS_IP' |
| _TOOLS_DIR = os.path.abspath(os.path.dirname(__file__)) |
| _BISECT_SCRIPT_PATH = os.path.join( |
| _TOOLS_DIR, 'auto_bisect', 'bisect_perf_regression.py') |
| |
| sys.path.append(os.path.join(_TOOLS_DIR, 'perf')) |
| from chrome_telemetry_build import chromium_config |
| sys.path.append(chromium_config.GetTelemetryDir()) |
| from telemetry.internal.browser import browser_options |
| |
| |
| def _RunBisectionScript(options): |
| """Attempts to execute the bisect script (bisect_perf_regression.py). |
| |
| Args: |
| options: The configuration options to pass to the bisect script. |
| |
| Returns: |
| An exit code; 0 for success, 1 for failure. |
| """ |
| script_path = os.path.join(options.working_directory, |
| 'bisect', 'src', 'tools','bisect-manual-test.py') |
| abs_script_path = os.path.abspath(script_path) |
| |
| test_command = ('python %s --browser=%s --chrome-root=.' % |
| (abs_script_path, options.browser_type)) |
| |
| cmd = ['python', _BISECT_SCRIPT_PATH, |
| '-c', test_command, |
| '-g', options.good_revision, |
| '-b', options.bad_revision, |
| '-m', 'manual_test/manual_test', |
| '-r', '1', |
| '--working_directory', options.working_directory, |
| '--build_preference', 'ninja', |
| '--no_custom_deps', |
| '--builder_type', options.builder_type] |
| |
| if options.extra_src: |
| cmd.extend(['--extra_src', options.extra_src]) |
| |
| if 'cros' in options.browser_type: |
| cmd.extend(['--target_platform', 'cros']) |
| |
| if os.environ[CROS_BOARD_ENV] and os.environ[CROS_IP_ENV]: |
| cmd.extend(['--cros_board', os.environ[CROS_BOARD_ENV]]) |
| cmd.extend(['--cros_remote_ip', os.environ[CROS_IP_ENV]]) |
| else: |
| print ('Error: Cros build selected, but BISECT_CROS_IP or' |
| 'BISECT_CROS_BOARD undefined.\n') |
| return 1 |
| elif 'android-chrome' == options.browser_type: |
| if not options.extra_src: |
| print 'Error: Missing --extra_src to run bisect for android-chrome.' |
| sys.exit(-1) |
| cmd.extend(['--target_platform', 'android-chrome']) |
| elif 'android' in options.browser_type: |
| cmd.extend(['--target_platform', 'android']) |
| elif not options.target_build_type: |
| cmd.extend(['--target_build_type', options.browser_type.title()]) |
| |
| if options.target_build_type: |
| cmd.extend(['--target_build_type', options.target_build_type]) |
| |
| if options.goma_threads: |
| cmd.extend(['--use_goma', '--goma_threads', options.goma_threads]) |
| |
| cmd = [str(c) for c in cmd] |
| |
| return_code = subprocess.call(cmd) |
| |
| if return_code: |
| print 'Error: bisect_perf_regression.py had exit code %d.' % return_code |
| print |
| |
| return return_code |
| |
| |
| def main(): |
| """Does a bisect based on the command-line arguments passed in. |
| |
| The user will be prompted to classify each revision as good or bad. |
| """ |
| usage = ('%prog [options]\n' |
| 'Used to run the bisection script with a manual test.') |
| |
| options = browser_options.BrowserFinderOptions('release') |
| parser = options.CreateParser(usage) |
| |
| parser.add_option('-b', '--bad_revision', |
| type='str', |
| help='A bad revision to start bisection. ' + |
| 'Must be later than good revision. May be either a git' + |
| ' or svn revision.') |
| parser.add_option('-g', '--good_revision', |
| type='str', |
| help='A revision to start bisection where performance' + |
| ' test is known to pass. Must be earlier than the ' + |
| 'bad revision. May be either a git or svn revision.') |
| parser.add_option('-w', '--working_directory', |
| type='str', |
| default='..', |
| help='A working directory to supply to the bisection ' |
| 'script, which will use it as the location to checkout ' |
| 'a copy of the chromium depot.') |
| parser.add_option('--extra_src', |
| type='str', |
| help='Path to extra source file. If this is supplied, ' |
| 'bisect script will use this to override default behavior.') |
| parser.add_option('--target_build_type', |
| type='choice', |
| choices=['Release', 'Debug'], |
| help='The target build type. Choices are "Release" ' |
| 'or "Debug".') |
| parser.add_option('--goma_threads', default=64, |
| type='int', |
| help='Number of goma threads to use. 0 will disable goma.') |
| parser.add_option('--builder_type', default='', |
| choices=['perf', |
| 'full', |
| 'android-chrome-perf', ''], |
| help='Type of builder to get build from. This allows ' |
| 'script to use cached builds. By default (empty), binaries ' |
| 'are built locally.') |
| options, _ = parser.parse_args() |
| error_msg = '' |
| if not options.good_revision: |
| error_msg += 'Error: missing required parameter: --good_revision\n' |
| if not options.bad_revision: |
| error_msg += 'Error: missing required parameter: --bad_revision\n' |
| |
| if error_msg: |
| print error_msg |
| parser.print_help() |
| return 1 |
| |
| if 'android' not in options.browser_type and sys.platform.startswith('linux'): |
| if not os.environ.get('CHROME_DEVEL_SANDBOX'): |
| print 'SUID sandbox has not been setup.'\ |
| ' See https://chromium.googlesource.com/chromium/src/'\ |
| '+/master/docs/linux_suid_sandbox_development.md.' |
| return 1 |
| |
| return _RunBisectionScript(options) |
| |
| |
| if __name__ == '__main__': |
| sys.exit(main()) |