OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 import 'dart:async'; |
| 6 import 'dart:convert'; |
| 7 import 'dart:io'; |
| 8 import 'dart:math' as math; |
| 9 |
| 10 import 'package:analyzer/file_system/file_system.dart'; |
| 11 import 'package:analyzer/file_system/physical_file_system.dart'; |
| 12 import 'package:args/command_runner.dart'; |
| 13 import 'package:intl/intl.dart'; |
| 14 import 'package:path/path.dart' as path; |
| 15 |
| 16 import 'perf/benchmarks_impl.dart'; |
| 17 |
| 18 Future main(List<String> args) async { |
| 19 final List<Benchmark> benchmarks = [ |
| 20 new ColdAnalysisBenchmark(), |
| 21 new AnalysisBenchmark(), |
| 22 ]; |
| 23 |
| 24 CommandRunner runner = new CommandRunner( |
| 25 'benchmark', 'A benchmark runner for the analysis server.'); |
| 26 runner.addCommand(new ListCommand(benchmarks)); |
| 27 runner.addCommand(new RunCommand(benchmarks)); |
| 28 runner.run(args); |
| 29 } |
| 30 |
| 31 class ListCommand extends Command { |
| 32 final List<Benchmark> benchmarks; |
| 33 |
| 34 ListCommand(this.benchmarks) { |
| 35 argParser.addFlag('machine', |
| 36 negatable: false, help: 'Emit the list of benchmarks as json.'); |
| 37 } |
| 38 |
| 39 @override |
| 40 String get name => 'list'; |
| 41 |
| 42 @override |
| 43 String get description => 'List available benchmarks.'; |
| 44 |
| 45 @override |
| 46 String get invocation => '${runner.executableName} $name'; |
| 47 |
| 48 void run() { |
| 49 if (argResults['machine']) { |
| 50 final Map map = { |
| 51 'benchmarks': benchmarks.map((b) => b.toJson()).toList() |
| 52 }; |
| 53 print(new JsonEncoder.withIndent(' ').convert(map)); |
| 54 } else { |
| 55 for (Benchmark benchmark in benchmarks) { |
| 56 print('${benchmark.id}: ${benchmark.description}'); |
| 57 } |
| 58 } |
| 59 } |
| 60 } |
| 61 |
| 62 class RunCommand extends Command { |
| 63 final List<Benchmark> benchmarks; |
| 64 |
| 65 RunCommand(this.benchmarks) { |
| 66 argParser.addFlag('quick', |
| 67 negatable: false, |
| 68 help: 'Run a quick version of the benchmark. This is ' |
| 69 'not useful for gathering accurate times, but can be used to ' |
| 70 'validate that the benchmark works.'); |
| 71 argParser.addOption('repeat', |
| 72 defaultsTo: '10', help: 'The number of times to repeat the benchmark.'); |
| 73 } |
| 74 |
| 75 @override |
| 76 String get name => 'run'; |
| 77 |
| 78 @override |
| 79 String get description => 'Run a given benchmark.'; |
| 80 |
| 81 @override |
| 82 String get invocation => '${runner.executableName} $name <benchmark-id>'; |
| 83 |
| 84 Future run() async { |
| 85 if (argResults.rest.isEmpty) { |
| 86 printUsage(); |
| 87 exit(1); |
| 88 } |
| 89 |
| 90 final String benchmarkId = argResults.rest.first; |
| 91 final int repeatCount = int.parse(argResults['repeat']); |
| 92 final bool quick = argResults['quick']; |
| 93 |
| 94 final Benchmark benchmark = |
| 95 benchmarks.firstWhere((b) => b.id == benchmarkId, orElse: () { |
| 96 print("Benchmark '$benchmarkId' not found."); |
| 97 exit(1); |
| 98 }); |
| 99 |
| 100 int actualIterations = repeatCount; |
| 101 if (benchmark.maxIterations > 0) { |
| 102 actualIterations = math.min(benchmark.maxIterations, repeatCount); |
| 103 } |
| 104 |
| 105 try { |
| 106 BenchMarkResult result; |
| 107 Stopwatch time = new Stopwatch()..start(); |
| 108 print('Running $benchmarkId $actualIterations times...'); |
| 109 |
| 110 for (int iteration = 0; iteration < actualIterations; iteration++) { |
| 111 BenchMarkResult newResult = await benchmark.run(quick: quick); |
| 112 print(' $newResult'); |
| 113 result = result == null ? newResult : result.combine(newResult); |
| 114 } |
| 115 |
| 116 time.stop(); |
| 117 print('Finished in ${time.elapsed.inSeconds} seconds.\n'); |
| 118 Map m = { |
| 119 'benchmark': benchmarkId, |
| 120 'result': result.toJson(), |
| 121 }; |
| 122 print(JSON.encode(m)); |
| 123 } catch (error, st) { |
| 124 print('$benchmarkId threw exception: $error'); |
| 125 print(st); |
| 126 exit(1); |
| 127 } |
| 128 } |
| 129 } |
| 130 |
| 131 abstract class Benchmark { |
| 132 final String id; |
| 133 final String description; |
| 134 final bool enabled; |
| 135 |
| 136 /// One of 'memory' or 'cpu'. |
| 137 final String kind; |
| 138 |
| 139 Benchmark(this.id, this.description, {this.enabled: true, this.kind: 'cpu'}); |
| 140 |
| 141 Future<BenchMarkResult> run({bool quick: false}); |
| 142 |
| 143 int get maxIterations => 0; |
| 144 |
| 145 Map toJson() => |
| 146 {'id': id, 'description': description, 'enabled': enabled, 'kind': kind}; |
| 147 |
| 148 String toString() => '$id: $description'; |
| 149 } |
| 150 |
| 151 class BenchMarkResult { |
| 152 static final NumberFormat nf = new NumberFormat.decimalPattern(); |
| 153 |
| 154 /// One of 'bytes', 'micros', or 'compound'. |
| 155 final String kindName; |
| 156 |
| 157 final int value; |
| 158 |
| 159 BenchMarkResult(this.kindName, this.value); |
| 160 |
| 161 BenchMarkResult combine(BenchMarkResult other) { |
| 162 return new BenchMarkResult(kindName, math.min(value, other.value)); |
| 163 } |
| 164 |
| 165 Map toJson() => {kindName: value}; |
| 166 |
| 167 String toString() => '$kindName: ${nf.format(value)}'; |
| 168 } |
| 169 |
| 170 class CompoundBenchMarkResult extends BenchMarkResult { |
| 171 final String name; |
| 172 |
| 173 CompoundBenchMarkResult(this.name) : super('compound', 0); |
| 174 |
| 175 Map<String, BenchMarkResult> results = {}; |
| 176 |
| 177 void add(String name, BenchMarkResult result) { |
| 178 results[name] = result; |
| 179 } |
| 180 |
| 181 BenchMarkResult combine(BenchMarkResult other) { |
| 182 BenchMarkResult _combine(BenchMarkResult a, BenchMarkResult b) { |
| 183 if (a == null) return b; |
| 184 if (b == null) return a; |
| 185 return a.combine(b); |
| 186 } |
| 187 |
| 188 CompoundBenchMarkResult o = other as CompoundBenchMarkResult; |
| 189 |
| 190 CompoundBenchMarkResult combined = new CompoundBenchMarkResult(name); |
| 191 List<String> keys = |
| 192 (new Set()..addAll(results.keys)..addAll(o.results.keys)).toList(); |
| 193 |
| 194 for (String key in keys) { |
| 195 combined.add(key, _combine(results[key], o.results[key])); |
| 196 } |
| 197 |
| 198 return combined; |
| 199 } |
| 200 |
| 201 Map toJson() { |
| 202 Map m = {}; |
| 203 for (String key in results.keys) { |
| 204 m['$name-$key'] = results[key].toJson(); |
| 205 } |
| 206 return m; |
| 207 } |
| 208 |
| 209 String toString() => '${toJson()}'; |
| 210 } |
| 211 |
| 212 List<String> getProjectRoots({bool quick: false}) { |
| 213 String script = Platform.script.toFilePath(windows: Platform.isWindows); |
| 214 String pkgPath = path.normalize(path.join(path.dirname(script), '..', '..')); |
| 215 return <String>[path.join(pkgPath, quick ? 'meta' : 'analysis_server')]; |
| 216 } |
| 217 |
| 218 String get analysisServerSrcPath { |
| 219 String script = Platform.script.toFilePath(windows: Platform.isWindows); |
| 220 String pkgPath = path.normalize(path.join(path.dirname(script), '..', '..')); |
| 221 return path.join(pkgPath, 'analysis_server'); |
| 222 } |
| 223 |
| 224 void deleteServerCache() { |
| 225 // ~/.dartServer/.analysis-driver/ |
| 226 ResourceProvider resourceProvider = PhysicalResourceProvider.INSTANCE; |
| 227 Folder stateLocation = resourceProvider.getStateLocation('.analysis-driver'); |
| 228 stateLocation.delete(); |
| 229 } |
OLD | NEW |