Trace-based benchmarking via a mojo app. This patch adds `benchmark.mojo` app for trace-based benchmarking and a runner script. $ mojo/devtools/common/mojo_benchmark mojo/tools/data/benchmarks [Trace me] measurement: time_until/trace_me/DoWork 4488.810000 measurement: avg_duration/trace_me/DoWork 300.449714 [Spinning cube] measurement: time_until/gpu/GpuScheduler:PutChanged 4341.874000 Fixes #371. R=etiennej@chromium.org, jamesr@chromium.org Review URL: https://codereview.chromium.org/1305193002 . Cr-Mirrored-From: https://github.com/domokit/mojo Cr-Mirrored-Commit: 1d909941168487e5a0c7f81f6b7c73c026c63054
diff --git a/mojo_benchmark b/mojo_benchmark new file mode 100755 index 0000000..7de9e61 --- /dev/null +++ b/mojo_benchmark
@@ -0,0 +1,126 @@ +#!/usr/bin/env python +# Copyright 2015 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. + +"""Runner for Mojo application benchmarks.""" + +import argparse +import logging +import sys + +from devtoolslib import shell_arguments +from devtoolslib import shell_config + + +_DESCRIPTION = """Runner for Mojo application benchmarks. + +|benchmark_list_file| has to be a valid Python program that sets a |benchmarks| +global variable, containing entries of the following form: + + { + 'name': '<name of the benchmark>', + 'app': '<url of the app to benchmark>', + 'shell-args': [], + 'duration': <duration in seconds>, + + # List of measurements to make. + 'measurements': [ + '<measurement type>/<event category>/<event name>', + ] + } + +Available measurement types are: + + - 'time_until' - time until the first occurence of the targeted event + - 'avg_duration' - average duration of the targeted event + +|benchmark_list_file| may reference the |target_os| global that will be any of +['android', 'linux'], indicating the system on which the benchmarks are to be +run. +""" + +_logger = logging.getLogger() + +_BENCHMARK_APP = 'https://core.mojoapps.io/benchmark.mojo' + +# Additional time in seconds allocated per shell run to accommodate start-up. +# The shell should terminate before hitting this time out, it is an error if it +# doesn't. +_EXTRA_TIMEOUT = 20 + + +def _run_benchmark(shell, shell_args, name, app, duration_seconds, measurements, + verbose): + """Runs `benchmark.mojo` in a shell with correct arguments, parses and + presents the benchmark results. + """ + timeout = duration_seconds + _EXTRA_TIMEOUT + benchmark_args = [] + benchmark_args.append('--app=' + app) + benchmark_args.append('--duration=' + str(duration_seconds)) + for measurement in measurements: + benchmark_args.append(measurement) + shell_args.append(_BENCHMARK_APP) + shell_args.append('--args-for=%s %s' % (_BENCHMARK_APP, + ' '.join(benchmark_args))) + if verbose: + print 'shell arguments: ' + str(shell_args) + print '[' + name + ']' + return_code, output, did_time_out = shell.run_and_get_output( + shell_args, timeout=timeout) + output_lines = [line.strip() for line in output.split('\n')] + + if return_code or did_time_out or 'benchmark succeeded' not in output_lines: + print 'timed out' if did_time_out else 'failed' + if return_code: + print 'Return code: ' + str(return_code) + print 'Output: ' + print output + print '-' * 72 + return False + + # Echo measurement results. + for line in output_lines: + if line.strip().startswith('measurement:'): + print line + return True + + +def main(): + parser = argparse.ArgumentParser( + formatter_class=argparse.RawDescriptionHelpFormatter, + description=_DESCRIPTION) + parser.add_argument('benchmark_list_file', type=file, + help='a file listing benchmarks to run') + + # Common shell configuration arguments. + shell_config.add_shell_arguments(parser) + script_args = parser.parse_args() + config = shell_config.get_shell_config(script_args) + + try: + shell, common_shell_args = shell_arguments.get_shell(config, []) + except shell_arguments.ShellConfigurationException as e: + print e + return 1 + + target_os = 'android' if script_args.android else 'linux' + benchmark_list_params = {"target_os": target_os} + exec script_args.benchmark_list_file in benchmark_list_params + benchmark_list = benchmark_list_params['benchmarks'] + + succeeded = True + for benchmark_spec in benchmark_list: + name = benchmark_spec['name'] + app = benchmark_spec['app'] + duration = benchmark_spec['duration'] + shell_args = benchmark_spec.get('shell-args', []) + common_shell_args + measurements = benchmark_spec['measurements'] + _run_benchmark(shell, shell_args, name, app, duration, measurements, + script_args.verbose) + + return 0 if succeeded else 1 + +if __name__ == '__main__': + sys.exit(main())