| Index: pkg/analysis_server/benchmark/benchmarks.dart
|
| diff --git a/pkg/analysis_server/benchmark/benchmarks.dart b/pkg/analysis_server/benchmark/benchmarks.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..aed89bbe452f1fe853c145b69d44c0672af4cbe5
|
| --- /dev/null
|
| +++ b/pkg/analysis_server/benchmark/benchmarks.dart
|
| @@ -0,0 +1,229 @@
|
| +// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
|
| +// for details. All rights reserved. Use of this source code is governed by a
|
| +// BSD-style license that can be found in the LICENSE file.
|
| +
|
| +import 'dart:async';
|
| +import 'dart:convert';
|
| +import 'dart:io';
|
| +import 'dart:math' as math;
|
| +
|
| +import 'package:analyzer/file_system/file_system.dart';
|
| +import 'package:analyzer/file_system/physical_file_system.dart';
|
| +import 'package:args/command_runner.dart';
|
| +import 'package:intl/intl.dart';
|
| +import 'package:path/path.dart' as path;
|
| +
|
| +import 'perf/benchmarks_impl.dart';
|
| +
|
| +Future main(List<String> args) async {
|
| + final List<Benchmark> benchmarks = [
|
| + new ColdAnalysisBenchmark(),
|
| + new AnalysisBenchmark(),
|
| + ];
|
| +
|
| + CommandRunner runner = new CommandRunner(
|
| + 'benchmark', 'A benchmark runner for the analysis server.');
|
| + runner.addCommand(new ListCommand(benchmarks));
|
| + runner.addCommand(new RunCommand(benchmarks));
|
| + runner.run(args);
|
| +}
|
| +
|
| +class ListCommand extends Command {
|
| + final List<Benchmark> benchmarks;
|
| +
|
| + ListCommand(this.benchmarks) {
|
| + argParser.addFlag('machine',
|
| + negatable: false, help: 'Emit the list of benchmarks as json.');
|
| + }
|
| +
|
| + @override
|
| + String get name => 'list';
|
| +
|
| + @override
|
| + String get description => 'List available benchmarks.';
|
| +
|
| + @override
|
| + String get invocation => '${runner.executableName} $name';
|
| +
|
| + void run() {
|
| + if (argResults['machine']) {
|
| + final Map map = {
|
| + 'benchmarks': benchmarks.map((b) => b.toJson()).toList()
|
| + };
|
| + print(new JsonEncoder.withIndent(' ').convert(map));
|
| + } else {
|
| + for (Benchmark benchmark in benchmarks) {
|
| + print('${benchmark.id}: ${benchmark.description}');
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +class RunCommand extends Command {
|
| + final List<Benchmark> benchmarks;
|
| +
|
| + RunCommand(this.benchmarks) {
|
| + argParser.addFlag('quick',
|
| + negatable: false,
|
| + help: 'Run a quick version of the benchmark. This is '
|
| + 'not useful for gathering accurate times, but can be used to '
|
| + 'validate that the benchmark works.');
|
| + argParser.addOption('repeat',
|
| + defaultsTo: '10', help: 'The number of times to repeat the benchmark.');
|
| + }
|
| +
|
| + @override
|
| + String get name => 'run';
|
| +
|
| + @override
|
| + String get description => 'Run a given benchmark.';
|
| +
|
| + @override
|
| + String get invocation => '${runner.executableName} $name <benchmark-id>';
|
| +
|
| + Future run() async {
|
| + if (argResults.rest.isEmpty) {
|
| + printUsage();
|
| + exit(1);
|
| + }
|
| +
|
| + final String benchmarkId = argResults.rest.first;
|
| + final int repeatCount = int.parse(argResults['repeat']);
|
| + final bool quick = argResults['quick'];
|
| +
|
| + final Benchmark benchmark =
|
| + benchmarks.firstWhere((b) => b.id == benchmarkId, orElse: () {
|
| + print("Benchmark '$benchmarkId' not found.");
|
| + exit(1);
|
| + });
|
| +
|
| + int actualIterations = repeatCount;
|
| + if (benchmark.maxIterations > 0) {
|
| + actualIterations = math.min(benchmark.maxIterations, repeatCount);
|
| + }
|
| +
|
| + try {
|
| + BenchMarkResult result;
|
| + Stopwatch time = new Stopwatch()..start();
|
| + print('Running $benchmarkId $actualIterations times...');
|
| +
|
| + for (int iteration = 0; iteration < actualIterations; iteration++) {
|
| + BenchMarkResult newResult = await benchmark.run(quick: quick);
|
| + print(' $newResult');
|
| + result = result == null ? newResult : result.combine(newResult);
|
| + }
|
| +
|
| + time.stop();
|
| + print('Finished in ${time.elapsed.inSeconds} seconds.\n');
|
| + Map m = {
|
| + 'benchmark': benchmarkId,
|
| + 'result': result.toJson(),
|
| + };
|
| + print(JSON.encode(m));
|
| + } catch (error, st) {
|
| + print('$benchmarkId threw exception: $error');
|
| + print(st);
|
| + exit(1);
|
| + }
|
| + }
|
| +}
|
| +
|
| +abstract class Benchmark {
|
| + final String id;
|
| + final String description;
|
| + final bool enabled;
|
| +
|
| + /// One of 'memory' or 'cpu'.
|
| + final String kind;
|
| +
|
| + Benchmark(this.id, this.description, {this.enabled: true, this.kind: 'cpu'});
|
| +
|
| + Future<BenchMarkResult> run({bool quick: false});
|
| +
|
| + int get maxIterations => 0;
|
| +
|
| + Map toJson() =>
|
| + {'id': id, 'description': description, 'enabled': enabled, 'kind': kind};
|
| +
|
| + String toString() => '$id: $description';
|
| +}
|
| +
|
| +class BenchMarkResult {
|
| + static final NumberFormat nf = new NumberFormat.decimalPattern();
|
| +
|
| + /// One of 'bytes', 'micros', or 'compound'.
|
| + final String kindName;
|
| +
|
| + final int value;
|
| +
|
| + BenchMarkResult(this.kindName, this.value);
|
| +
|
| + BenchMarkResult combine(BenchMarkResult other) {
|
| + return new BenchMarkResult(kindName, math.min(value, other.value));
|
| + }
|
| +
|
| + Map toJson() => {kindName: value};
|
| +
|
| + String toString() => '$kindName: ${nf.format(value)}';
|
| +}
|
| +
|
| +class CompoundBenchMarkResult extends BenchMarkResult {
|
| + final String name;
|
| +
|
| + CompoundBenchMarkResult(this.name) : super('compound', 0);
|
| +
|
| + Map<String, BenchMarkResult> results = {};
|
| +
|
| + void add(String name, BenchMarkResult result) {
|
| + results[name] = result;
|
| + }
|
| +
|
| + BenchMarkResult combine(BenchMarkResult other) {
|
| + BenchMarkResult _combine(BenchMarkResult a, BenchMarkResult b) {
|
| + if (a == null) return b;
|
| + if (b == null) return a;
|
| + return a.combine(b);
|
| + }
|
| +
|
| + CompoundBenchMarkResult o = other as CompoundBenchMarkResult;
|
| +
|
| + CompoundBenchMarkResult combined = new CompoundBenchMarkResult(name);
|
| + List<String> keys =
|
| + (new Set()..addAll(results.keys)..addAll(o.results.keys)).toList();
|
| +
|
| + for (String key in keys) {
|
| + combined.add(key, _combine(results[key], o.results[key]));
|
| + }
|
| +
|
| + return combined;
|
| + }
|
| +
|
| + Map toJson() {
|
| + Map m = {};
|
| + for (String key in results.keys) {
|
| + m['$name-$key'] = results[key].toJson();
|
| + }
|
| + return m;
|
| + }
|
| +
|
| + String toString() => '${toJson()}';
|
| +}
|
| +
|
| +List<String> getProjectRoots({bool quick: false}) {
|
| + String script = Platform.script.toFilePath(windows: Platform.isWindows);
|
| + String pkgPath = path.normalize(path.join(path.dirname(script), '..', '..'));
|
| + return <String>[path.join(pkgPath, quick ? 'meta' : 'analysis_server')];
|
| +}
|
| +
|
| +String get analysisServerSrcPath {
|
| + String script = Platform.script.toFilePath(windows: Platform.isWindows);
|
| + String pkgPath = path.normalize(path.join(path.dirname(script), '..', '..'));
|
| + return path.join(pkgPath, 'analysis_server');
|
| +}
|
| +
|
| +void deleteServerCache() {
|
| + // ~/.dartServer/.analysis-driver/
|
| + ResourceProvider resourceProvider = PhysicalResourceProvider.INSTANCE;
|
| + Folder stateLocation = resourceProvider.getStateLocation('.analysis-driver');
|
| + stateLocation.delete();
|
| +}
|
|
|