예제 #1
0
    def CreateParser(self, *args, **kwargs):
        parser = optparse.OptionParser(*args, **kwargs)

        # Options to interact with a potential external results processor.
        parser.set_defaults(
            external_results_processor=False,
            intermediate_dir=None,
            # TODO(crbug.com/928275): Remove these when Telemetry is no longer
            # involved in any results processing.
            output_dir=None,
            output_formats=[],
            legacy_output_formats=[],
            reset_results=True,
            results_label='telemetry_run',
            upload_results=False,
            upload_bucket=None)

        # Selection group
        group = optparse.OptionGroup(parser, 'Which browser to use')
        group.add_option('--browser',
                         dest='browser_type',
                         default=None,
                         help='Browser type to run, '
                         'in order of priority. Supported values: list,%s' %
                         ', '.join(browser_finder.FindAllBrowserTypes()))
        group.add_option('--browser-executable',
                         dest='browser_executable',
                         help='The exact browser to run.')
        group.add_option('--chrome-root',
                         dest='chrome_root',
                         help='Where to look for chrome builds. '
                         'Defaults to searching parent dirs by default.')
        group.add_option(
            '--chromium-output-directory',
            dest='chromium_output_dir',
            help='Where to look for build artifacts. '
            'Can also be specified by setting environment variable '
            'CHROMIUM_OUTPUT_DIR.')
        group.add_option(
            '--remote',
            dest='cros_remote',
            help='The hostname of a remote ChromeOS device to use.')
        group.add_option(
            '--remote-ssh-port',
            type=int,
            default=socket.getservbyname('ssh'),
            dest='cros_remote_ssh_port',
            help=
            'The SSH port of the remote ChromeOS device (requires --remote).')
        compat_mode_options_list = [
            compat_mode_options.NO_FIELD_TRIALS,
            compat_mode_options.IGNORE_CERTIFICATE_ERROR,
            compat_mode_options.LEGACY_COMMAND_LINE_PATH,
            compat_mode_options.GPU_BENCHMARKING_FALLBACKS,
            compat_mode_options.DONT_REQUIRE_ROOTED_DEVICE
        ]
        parser.add_option(
            '--compatibility-mode',
            action='append',
            dest='compatibility_mode',
            choices=compat_mode_options_list,
            default=[],
            help='Select the compatibility change that you want to enforce when '
            'running benchmarks. The options are: %s' %
            ', '.join(compat_mode_options_list))
        parser.add_option(
            '--experimental-proto-trace-format',
            action='store_true',
            help='Request traces from Chrome in protobuf file format.')
        identity = None
        testing_rsa = os.path.join(util.GetTelemetryThirdPartyDir(),
                                   'chromite', 'ssh_keys', 'testing_rsa')
        if os.path.exists(testing_rsa):
            identity = testing_rsa
        group.add_option(
            '--identity',
            dest='cros_ssh_identity',
            default=identity,
            help=
            'The identity file to use when ssh\'ing into the ChromeOS device')
        parser.add_option_group(group)

        # Debugging options
        group = optparse.OptionGroup(parser, 'When things go wrong')
        group.add_option('--print-bootstrap-deps',
                         action='store_true',
                         help='Output bootstrap deps list.')
        group.add_option(
            '--extra-chrome-categories',
            dest='extra_chrome_categories',
            type=str,
            help=
            'Filter string to enable additional chrome tracing categories. See'
            ' documentation here: https://cs.chromium.org/chromium/src/base/'
            'trace_event/trace_config.h?rcl='
            'c8db6c6371ca047c24d41f3972d5819bc83d83ae&l=125')
        group.add_option(
            '--extra-atrace-categories',
            dest='extra_atrace_categories',
            type=str,
            help='Comma-separated list of extra atrace categories. Use atrace'
            ' --list_categories to get full list.')
        group.add_option(
            '--enable-systrace',
            dest='enable_systrace',
            action='store_true',
            help='Enable collection of systrace. (Useful on ChromeOS where'
            ' atrace is not supported; collects scheduling information.)')
        parser.add_option_group(group)

        # Platform options
        group = optparse.OptionGroup(parser, 'Platform options')
        group.add_option(
            '--no-performance-mode',
            action='store_true',
            help='Some platforms run on "full performance mode" where the '
            'test is executed at maximum CPU speed in order to minimize noise '
            '(specially important for dashboards / continuous builds). '
            'This option prevents Telemetry from tweaking such platform settings.'
        )
        # TODO(crbug.com/1025207): Rename this to --support-apk
        group.add_option(
            '--webview-embedder-apk',
            action="append",
            default=[],
            help=
            'When running tests on android webview, more than one apk needs to'
            ' be installed. The apk running the test is said to embed webview. More'
            ' than one apk may be specified if needed.')
        parser.add_option_group(group)

        # Remote platform options
        group = optparse.OptionGroup(parser, 'Remote platform options')
        group.add_option('--android-blacklist-file',
                         help='Device blacklist JSON file.')
        group.add_option(
            '--device',
            help='The device ID to use. '
            'If not specified, only 0 or 1 connected devices are supported. '
            'If specified as "android", all available Android devices are '
            'used.')
        group.add_option(
            '--install-bundle-module',
            dest='modules_to_install',
            action='append',
            default=[],
            help=
            'Specify Android App Bundle modules to install in addition to the '
            'base module. Ignored on Non-Android platforms.')
        parser.add_option_group(group)

        group = optparse.OptionGroup(parser, 'Fuchsia platform options')
        group.add_option(
            '--fuchsia-output-dir',
            default='out/Release',
            help='Specify the build directory for the Fuchsia OS installed on '
            'the device.')
        parser.add_option_group(group)

        # CPU profiling on Android/Linux/ChromeOS.
        group = optparse.OptionGroup(
            parser, ('CPU profiling over intervals of interest, '
                     'Android, Linux, and ChromeOS only'))
        group.add_option(
            '--interval-profiling-target',
            dest='interval_profiling_target',
            default='renderer:main',
            metavar='PROCESS_NAME[:THREAD_NAME]|"system_wide"',
            help=
            'Run the CPU profiler on this process/thread (default=%default), '
            'which is supported only on Linux and Android, or system-wide, which '
            'is supported only on ChromeOS.')
        group.add_option(
            '--interval-profiling-period',
            dest='interval_profiling_periods',
            type='choice',
            choices=('navigation', 'interactions', 'story_run'),
            action='append',
            default=[],
            metavar='PERIOD',
            help='Run the CPU profiler during this test period. '
            'May be specified multiple times except when the story_run period is '
            'used; available choices are ["navigation", "interactions", '
            '"story_run"]. Profile data will be written to '
            'artifacts/*.perf.data (Android/ChromeOS) or '
            'artifacts/*.profile.pb (Linux) files in the output directory. See '
            'https://developer.android.com/ndk/guides/simpleperf for more info on '
            'Android profiling via simpleperf.')
        group.add_option(
            '--interval-profiling-frequency',
            default=1000,
            metavar='FREQUENCY',
            type=int,
            help='Frequency of CPU profiling samples, in samples per second '
            '(default=%default). This flag is used only on Android')
        group.add_option(
            '--interval-profiler-options',
            dest='interval_profiler_options',
            type=str,
            metavar='"--flag <options> ..."',
            help='Addtional arguments to pass to the CPU profiler. This is used '
            'only on ChromeOS. On ChromeOS, pass the linux perf\'s subcommand name '
            'followed by the options to pass to the perf tool. Supported perf '
            'subcommands are "record" and "stat". '
            'Eg: "record -e cycles -c 4000000 -g". Note: "-a" flag is added to the '
            'perf command by default. Do not pass options that are incompatible '
            'with the system-wide profile collection.')
        parser.add_option_group(group)

        # Browser options.
        self.browser_options.AddCommandLineArgs(parser)

        real_parse = parser.parse_args

        def ParseArgs(args=None):
            defaults = parser.get_default_values()
            for k, v in defaults.__dict__.items():
                if k in self.__dict__ and self.__dict__[k] != None:
                    continue
                self.__dict__[k] = v
            ret = real_parse(args, self)  # pylint: disable=E1121

            if self.chromium_output_dir:
                os.environ['CHROMIUM_OUTPUT_DIR'] = self.chromium_output_dir

            # Parse remote platform options.
            self.BuildRemotePlatformOptions()

            if self.remote_platform_options.device == 'list':
                if binary_manager.NeedsInit():
                    binary_manager.InitDependencyManager([])
                devices = device_finder.GetDevicesMatchingOptions(self)
                print 'Available devices:'
                for device in devices:
                    print ' ', device.name
                sys.exit(0)

            if self.browser_executable and not self.browser_type:
                self.browser_type = 'exact'
            if self.browser_type == 'list':
                if binary_manager.NeedsInit():
                    binary_manager.InitDependencyManager([])
                devices = device_finder.GetDevicesMatchingOptions(self)
                if not devices:
                    sys.exit(0)
                browser_types = {}
                for device in devices:
                    try:
                        possible_browsers = browser_finder.GetAllAvailableBrowsers(
                            self, device)
                        browser_types[device.name] = sorted([
                            browser.browser_type
                            for browser in possible_browsers
                        ])
                    except browser_finder_exceptions.BrowserFinderException as ex:
                        print >> sys.stderr, 'ERROR: ', ex
                        sys.exit(1)
                print 'Available browsers:'
                if len(browser_types) == 0:
                    print '  No devices were found.'
                for device_name in sorted(browser_types.keys()):
                    print '  ', device_name
                    for browser_type in browser_types[device_name]:
                        print '    ', browser_type
                    if len(browser_types[device_name]) == 0:
                        print '     No browsers found for this device'
                sys.exit(0)

            # Profiling other periods along with the story_run period leads to running
            # multiple profiling processes at the same time. The effects of performing
            # muliple CPU profiling at the same time is unclear and may generate
            # incorrect profiles so this will not be supported.
            if (len(self.interval_profiling_periods) > 1
                    and 'story_run' in self.interval_profiling_periods):
                print 'Cannot specify other periods along with the story_run period.'
                sys.exit(1)

            self.interval_profiler_options = shlex.split(
                self.interval_profiler_options)

            # Parse browser options.
            self.browser_options.UpdateFromParseResults(self)

            return ret

        parser.parse_args = ParseArgs
        return parser
예제 #2
0
    def CreateParser(self, *args, **kwargs):
        parser = optparse.OptionParser(*args, **kwargs)

        # Selection group
        group = optparse.OptionGroup(parser, 'Which browser to use')
        group.add_option('--browser',
                         dest='browser_type',
                         default=None,
                         help='Browser type to run, '
                         'in order of priority. Supported values: list,%s' %
                         ','.join(browser_finder.FindAllBrowserTypes(self)))
        group.add_option('--browser-executable',
                         dest='browser_executable',
                         help='The exact browser to run.')
        group.add_option('--chrome-root',
                         dest='chrome_root',
                         help='Where to look for chrome builds. '
                         'Defaults to searching parent dirs by default.')
        group.add_option(
            '--chromium-output-directory',
            dest='chromium_output_dir',
            help='Where to look for build artifacts. '
            'Can also be specified by setting environment variable '
            'CHROMIUM_OUTPUT_DIR.')
        group.add_option(
            '--remote',
            dest='cros_remote',
            help='The hostname of a remote ChromeOS device to use.')
        group.add_option(
            '--remote-ssh-port',
            type=int,
            default=socket.getservbyname('ssh'),
            dest='cros_remote_ssh_port',
            help=
            'The SSH port of the remote ChromeOS device (requires --remote).')
        parser.add_option(
            '--compatibility-mode',
            action='append',
            dest='compatibility_mode',
            choices=[
                compact_mode_options.NO_FIELD_TRIALS,
                compact_mode_options.IGNORE_CERTIFICATE_ERROR,
                compact_mode_options.LEGACY_COMMAND_LINE_PATH,
                compact_mode_options.GPU_BENCHMARKING_FALLBACKS
            ],
            default=[],
            help='Select the compatibility change that you want to enforce when '
            'running benchmarks')
        identity = None
        testing_rsa = os.path.join(util.GetTelemetryThirdPartyDir(),
                                   'chromite', 'ssh_keys', 'testing_rsa')
        if os.path.exists(testing_rsa):
            identity = testing_rsa
        group.add_option(
            '--identity',
            dest='cros_ssh_identity',
            default=identity,
            help=
            'The identity file to use when ssh\'ing into the ChromeOS device')
        parser.add_option_group(group)

        # Debugging options
        group = optparse.OptionGroup(parser, 'When things go wrong')
        group.add_option('-v',
                         '--verbose',
                         action='count',
                         dest='verbosity',
                         help='Increase verbosity level (repeat as needed)')
        group.add_option('--print-bootstrap-deps',
                         action='store_true',
                         help='Output bootstrap deps list.')
        group.add_option(
            '--extra-chrome-categories',
            dest='extra_chrome_categories',
            type=str,
            help=
            'Filter string to enable additional chrome tracing categories. See'
            ' documentation here: https://cs.chromium.org/chromium/src/base/'
            'trace_event/trace_config.h?rcl='
            'c8db6c6371ca047c24d41f3972d5819bc83d83ae&l=125')
        group.add_option(
            '--extra-atrace-categories',
            dest='extra_atrace_categories',
            type=str,
            help='Comma-separated list of extra atrace categories. Use atrace'
            ' --list_categories to get full list.')
        group.add_option(
            '--enable-systrace',
            dest='enable_systrace',
            action='store_true',
            help='Enable collection of systrace. (Useful on ChromeOS where'
            ' atrace is not supported; collects scheduling information.)')
        parser.add_option_group(group)

        # Platform options
        group = optparse.OptionGroup(parser, 'Platform options')
        group.add_option(
            '--no-performance-mode',
            action='store_true',
            help='Some platforms run on "full performance mode" where the '
            'test is executed at maximum CPU speed in order to minimize noise '
            '(specially important for dashboards / continuous builds). '
            'This option prevents Telemetry from tweaking such platform settings.'
        )
        group.add_option(
            '--webview-embedder-apk',
            help=
            'When running tests on android webview, more than one apk needs to'
            ' be installed. The apk running the test is said to embed webview.'
        )
        parser.add_option_group(group)

        # Remote platform options
        group = optparse.OptionGroup(parser, 'Remote platform options')
        group.add_option('--android-blacklist-file',
                         help='Device blacklist JSON file.')
        group.add_option(
            '--device',
            help='The device ID to use. '
            'If not specified, only 0 or 1 connected devices are supported. '
            'If specified as "android", all available Android devices are '
            'used.')
        parser.add_option_group(group)

        # CPU profiling on Android.
        group = optparse.OptionGroup(
            parser, ('CPU profiling over intervals of interest, '
                     'Android and Linux only'))
        group.add_option(
            '--interval-profiling-target',
            dest='interval_profiling_target',
            default='renderer:main',
            metavar='PROCESS_NAME[:THREAD_NAME]',
            help=
            'Run the CPU profiler on this process/thread (default=%default).')
        group.add_option(
            '--interval-profiling-period',
            dest='interval_profiling_periods',
            type='choice',
            choices=('navigation', 'interactions'),
            action='append',
            default=[],
            metavar='PERIOD',
            help='Run the CPU profiler during this test period. '
            'May be specified multiple times; available choices '
            'are ["navigation", "interactions"]. Profile data will be written to'
            'artifacts/*.perf.data (Android) or artifacts/*.profile.pb (Linux) '
            'files in the output directory. See '
            'https://developer.android.com/ndk/guides/simpleperf for more info on '
            'Android profiling via simpleperf.')
        group.add_option(
            '--interval-profiling-frequency',
            default=1000,
            metavar='FREQUENCY',
            type=int,
            help='Frequency of CPU profiling samples, in samples per second '
            '(default=%default).')
        parser.add_option_group(group)

        # Browser options.
        self.browser_options.AddCommandLineArgs(parser)

        real_parse = parser.parse_args

        def ParseArgs(args=None):
            defaults = parser.get_default_values()
            for k, v in defaults.__dict__.items():
                if k in self.__dict__ and self.__dict__[k] != None:
                    continue
                self.__dict__[k] = v
            ret = real_parse(args, self)  # pylint: disable=E1121

            if self.verbosity >= 2:
                global_hooks.InstallSpyOnPopenArgs()
                logging.getLogger().setLevel(logging.DEBUG)
            elif self.verbosity:
                logging.getLogger().setLevel(logging.INFO)
            else:
                logging.getLogger().setLevel(logging.WARNING)

            if self.chromium_output_dir:
                os.environ['CHROMIUM_OUTPUT_DIR'] = self.chromium_output_dir

            # Parse remote platform options.
            self.BuildRemotePlatformOptions()

            if self.remote_platform_options.device == 'list':
                if binary_manager.NeedsInit():
                    binary_manager.InitDependencyManager([])
                devices = device_finder.GetDevicesMatchingOptions(self)
                print 'Available devices:'
                for device in devices:
                    print ' ', device.name
                sys.exit(0)

            if self.browser_executable and not self.browser_type:
                self.browser_type = 'exact'
            if self.browser_type == 'list':
                if binary_manager.NeedsInit():
                    binary_manager.InitDependencyManager([])
                devices = device_finder.GetDevicesMatchingOptions(self)
                if not devices:
                    sys.exit(0)
                browser_types = {}
                for device in devices:
                    try:
                        possible_browsers = browser_finder.GetAllAvailableBrowsers(
                            self, device)
                        browser_types[device.name] = sorted([
                            browser.browser_type
                            for browser in possible_browsers
                        ])
                    except browser_finder_exceptions.BrowserFinderException as ex:
                        print >> sys.stderr, 'ERROR: ', ex
                        sys.exit(1)
                print 'Available browsers:'
                if len(browser_types) == 0:
                    print '  No devices were found.'
                for device_name in sorted(browser_types.keys()):
                    print '  ', device_name
                    for browser_type in browser_types[device_name]:
                        print '    ', browser_type
                    if len(browser_types[device_name]) == 0:
                        print '     No browsers found for this device'
                sys.exit(0)

            # Parse browser options.
            self.browser_options.UpdateFromParseResults(self)

            return ret

        parser.parse_args = ParseArgs
        return parser
예제 #3
0
    def CreateParser(self, *args, **kwargs):
        parser = optparse.OptionParser(*args, **kwargs)

        # Selection group
        group = optparse.OptionGroup(parser, 'Which browser to use')
        group.add_option('--browser',
                         dest='browser_type',
                         default=None,
                         help='Browser type to run, '
                         'in order of priority. Supported values: list,%s' %
                         ','.join(browser_finder.FindAllBrowserTypes(self)))
        group.add_option('--browser-executable',
                         dest='browser_executable',
                         help='The exact browser to run.')
        group.add_option('--chrome-root',
                         dest='chrome_root',
                         help='Where to look for chrome builds. '
                         'Defaults to searching parent dirs by default.')
        group.add_option(
            '--chromium-output-directory',
            dest='chromium_output_dir',
            help='Where to look for build artifacts. '
            'Can also be specified by setting environment variable '
            'CHROMIUM_OUTPUT_DIR.')
        group.add_option(
            '--remote',
            dest='cros_remote',
            help='The hostname of a remote ChromeOS device to use.')
        group.add_option(
            '--remote-ssh-port',
            type=int,
            default=socket.getservbyname('ssh'),
            dest='cros_remote_ssh_port',
            help=
            'The SSH port of the remote ChromeOS device (requires --remote).')
        identity = None
        testing_rsa = os.path.join(util.GetTelemetryThirdPartyDir(),
                                   'chromite', 'ssh_keys', 'testing_rsa')
        if os.path.exists(testing_rsa):
            identity = testing_rsa
        group.add_option(
            '--identity',
            dest='cros_ssh_identity',
            default=identity,
            help=
            'The identity file to use when ssh\'ing into the ChromeOS device')
        parser.add_option_group(group)

        # Debugging options
        group = optparse.OptionGroup(parser, 'When things go wrong')
        profiler_choices = profiler_finder.GetAllAvailableProfilers()
        group.add_option(
            '--profiler',
            default=None,
            type='choice',
            choices=profiler_choices,
            help='Record profiling data using this tool. Supported values: %s. '
            '(Notice: this flag cannot be used for Timeline Based Measurement '
            'benchmarks.)' % ', '.join(profiler_choices))
        group.add_option('-v',
                         '--verbose',
                         action='count',
                         dest='verbosity',
                         help='Increase verbosity level (repeat as needed)')
        group.add_option('--print-bootstrap-deps',
                         action='store_true',
                         help='Output bootstrap deps list.')
        parser.add_option_group(group)

        # Platform options
        group = optparse.OptionGroup(parser, 'Platform options')
        group.add_option(
            '--no-performance-mode',
            action='store_true',
            help='Some platforms run on "full performance mode" where the '
            'test is executed at maximum CPU speed in order to minimize noise '
            '(specially important for dashboards / continuous builds). '
            'This option prevents Telemetry from tweaking such platform settings.'
        )
        group.add_option(
            '--webview-embedder-apk',
            help=
            'When running tests on android webview, more than one apk needs to'
            ' be installed. The apk running the test is said to embed webview.'
        )
        parser.add_option_group(group)

        # Remote platform options
        group = optparse.OptionGroup(parser, 'Remote platform options')
        group.add_option('--android-blacklist-file',
                         help='Device blacklist JSON file.')
        group.add_option(
            '--device',
            help='The device ID to use. '
            'If not specified, only 0 or 1 connected devices are supported. '
            'If specified as "android", all available Android devices are '
            'used.')
        parser.add_option_group(group)

        # Browser options.
        self.browser_options.AddCommandLineArgs(parser)

        real_parse = parser.parse_args

        def ParseArgs(args=None):
            defaults = parser.get_default_values()
            for k, v in defaults.__dict__.items():
                if k in self.__dict__ and self.__dict__[k] != None:
                    continue
                self.__dict__[k] = v
            ret = real_parse(args, self)  # pylint: disable=E1121

            if self.verbosity >= 2:
                logging.getLogger().setLevel(logging.DEBUG)
            elif self.verbosity:
                logging.getLogger().setLevel(logging.INFO)
            else:
                logging.getLogger().setLevel(logging.WARNING)

            if self.chromium_output_dir:
                os.environ['CHROMIUM_OUTPUT_DIR'] = self.chromium_output_dir

            # Parse remote platform options.
            self.BuildRemotePlatformOptions()

            if self.remote_platform_options.device == 'list':
                if binary_manager.NeedsInit():
                    binary_manager.InitDependencyManager([])
                devices = device_finder.GetDevicesMatchingOptions(self)
                print 'Available devices:'
                for device in devices:
                    print ' ', device.name
                sys.exit(0)

            if self.browser_executable and not self.browser_type:
                self.browser_type = 'exact'
            if self.browser_type == 'list':
                if binary_manager.NeedsInit():
                    binary_manager.InitDependencyManager([])
                devices = device_finder.GetDevicesMatchingOptions(self)
                if not devices:
                    sys.exit(0)
                browser_types = {}
                for device in devices:
                    try:
                        possible_browsers = browser_finder.GetAllAvailableBrowsers(
                            self, device)
                        browser_types[device.name] = sorted([
                            browser.browser_type
                            for browser in possible_browsers
                        ])
                    except browser_finder_exceptions.BrowserFinderException as ex:
                        print >> sys.stderr, 'ERROR: ', ex
                        sys.exit(1)
                print 'Available browsers:'
                if len(browser_types) == 0:
                    print '  No devices were found.'
                for device_name in sorted(browser_types.keys()):
                    print '  ', device_name
                    for browser_type in browser_types[device_name]:
                        print '    ', browser_type
                sys.exit(0)

            # Parse browser options.
            self.browser_options.UpdateFromParseResults(self)

            return ret

        parser.parse_args = ParseArgs
        return parser
예제 #4
0
  def CreateParser(self, *args, **kwargs):
    parser = optparse.OptionParser(*args, **kwargs)

    # Selection group
    group = optparse.OptionGroup(parser, 'Which browser to use')
    group.add_option('--browser',
        dest='browser_type',
        default=None,
        help='Browser type to run, '
             'in order of priority. Supported values: list,%s' %
             ','.join(browser_finder.FindAllBrowserTypes(self)))
    group.add_option('--browser-executable',
        dest='browser_executable',
        help='The exact browser to run.')
    group.add_option('--chrome-root',
        dest='chrome_root',
        help='Where to look for chrome builds.'
             'Defaults to searching parent dirs by default.')
    group.add_option('--device',
        dest='device',
        help='The device ID to use.'
             'If not specified, only 0 or 1 connected devices are supported. If'
             'specified as "android", all available Android devices are used.')
    group.add_option('--target-arch',
        dest='target_arch',
        help='The target architecture of the browser. Options available are: '
             'x64, x86_64, arm, arm64 and mips. '
             'Defaults to the default architecture of the platform if omitted.')
    group.add_option(
        '--remote',
        dest='cros_remote',
        help='The hostname of a remote ChromeOS device to use.')
    group.add_option(
        '--remote-ssh-port',
        type=int,
        default=socket.getservbyname('ssh'),
        dest='cros_remote_ssh_port',
        help='The SSH port of the remote ChromeOS device (requires --remote).')
    identity = None
    testing_rsa = os.path.join(
        util.GetChromiumSrcDir(),
        'third_party', 'chromite', 'ssh_keys', 'testing_rsa')
    if os.path.exists(testing_rsa):
      identity = testing_rsa
    group.add_option('--identity',
        dest='cros_ssh_identity',
        default=identity,
        help='The identity file to use when ssh\'ing into the ChromeOS device')
    parser.add_option_group(group)

    # Debugging options
    group = optparse.OptionGroup(parser, 'When things go wrong')
    profiler_choices = profiler_finder.GetAllAvailableProfilers()
    group.add_option(
        '--profiler', default=None, type='choice',
        choices=profiler_choices,
        help='Record profiling data using this tool. Supported values: ' +
             ', '.join(profiler_choices))
    group.add_option(
        '-v', '--verbose', action='count', dest='verbosity',
        help='Increase verbosity level (repeat as needed)')
    group.add_option('--print-bootstrap-deps',
                     action='store_true',
                     help='Output bootstrap deps list.')
    parser.add_option_group(group)

    # Platform options
    group = optparse.OptionGroup(parser, 'Platform options')
    group.add_option('--no-performance-mode', action='store_true',
        help='Some platforms run on "full performance mode" where the '
        'test is executed at maximum CPU speed in order to minimize noise '
        '(specially important for dashboards / continuous builds). '
        'This option prevents Telemetry from tweaking such platform settings.')
    group.add_option('--android-rndis', dest='android_rndis', default=False,
        action='store_true', help='Use RNDIS forwarding on Android.')
    group.add_option('--no-android-rndis', dest='android_rndis',
        action='store_false', help='Do not use RNDIS forwarding on Android.'
        ' [default]')
    parser.add_option_group(group)

    # Browser options.
    self.browser_options.AddCommandLineArgs(parser)

    real_parse = parser.parse_args
    def ParseArgs(args=None):
      defaults = parser.get_default_values()
      for k, v in defaults.__dict__.items():
        if k in self.__dict__ and self.__dict__[k] != None:
          continue
        self.__dict__[k] = v
      ret = real_parse(args, self) # pylint: disable=E1121

      if self.verbosity >= 2:
        logging.getLogger().setLevel(logging.DEBUG)
      elif self.verbosity:
        logging.getLogger().setLevel(logging.INFO)
      else:
        logging.getLogger().setLevel(logging.WARNING)
      logging.basicConfig(
          format='%(levelname)s:%(name)s:%(asctime)s:%(message)s')

      if self.device == 'list':
        devices = device_finder.GetDevicesMatchingOptions(self)
        print 'Available devices:'
        for device in devices:
          print ' ', device.name
        sys.exit(0)

      if self.browser_executable and not self.browser_type:
        self.browser_type = 'exact'
      if self.browser_type == 'list':
        devices = device_finder.GetDevicesMatchingOptions(self)
        if not devices:
          sys.exit(0)
        browser_types = {}
        for device in devices:
          try:
            possible_browsers = browser_finder.GetAllAvailableBrowsers(self,
                                                                       device)
            browser_types[device.name] = sorted(
              [browser.browser_type for browser in possible_browsers])
          except browser_finder_exceptions.BrowserFinderException as ex:
            print >> sys.stderr, 'ERROR: ', ex
            sys.exit(1)
        print 'Available browsers:'
        if len(browser_types) == 0:
          print '  No devices were found.'
        for device_name in sorted(browser_types.keys()):
          print '  ', device_name
          for browser_type in browser_types[device_name]:
            print '    ', browser_type
        sys.exit(0)

      # Parse browser options.
      self.browser_options.UpdateFromParseResults(self)

      return ret
    parser.parse_args = ParseArgs
    return parser