| // Copyright (c) 2022, 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:io'; | |
| import 'package:benchmark_harness/benchmark_harness.dart'; | |
| import '../bin/collect_coverage.dart' as collect_coverage; | |
| import '../bin/format_coverage.dart' as format_coverage; | |
| // Runs a test script with various different coverage configurations. | |
| class CoverageBenchmark extends AsyncBenchmarkBase { | |
| CoverageBenchmark( | |
| ScoreEmitter emitter, | |
| super.name, | |
| this.script, { | |
| this.gatherCoverage = false, | |
| this.functionCoverage = false, | |
| this.branchCoverage = false, | |
| }) : super(emitter: emitter); | |
| final String script; | |
| final bool gatherCoverage; | |
| final bool functionCoverage; | |
| final bool branchCoverage; | |
| int iteration = 0; | |
| @override | |
| Future<void> run() async { | |
| print('Running $name...'); | |
| final covFile = 'data/$name $iteration coverage.json'; | |
| final lcovFile = 'data/$name $iteration lcov.info'; | |
| ++iteration; | |
| await Process.start(Platform.executable, [ | |
| if (branchCoverage) '--branch-coverage', | |
| 'run', | |
| if (gatherCoverage) ...[ | |
| '--pause-isolates-on-exit', | |
| '--disable-service-auth-codes', | |
| '--enable-vm-service=1234', | |
| ], | |
| script, | |
| ], mode: ProcessStartMode.detached); | |
| if (gatherCoverage) { | |
| await collect_coverage.main([ | |
| '--wait-paused', | |
| '--resume-isolates', | |
| '--uri=http://127.0.0.1:1234/', | |
| if (branchCoverage) '--branch-coverage', | |
| if (functionCoverage) '--function-coverage', | |
| '-o', | |
| covFile, | |
| ]); | |
| await format_coverage.main([ | |
| '--lcov', | |
| '--check-ignore', | |
| '-i', | |
| covFile, | |
| '-o', | |
| lcovFile, | |
| ]); | |
| } | |
| } | |
| } | |
| // Emitter that just captures the value. | |
| class CaptureEmitter implements ScoreEmitter { | |
| late double capturedValue; | |
| @override | |
| void emit(String testName, double value) { | |
| capturedValue = value; | |
| } | |
| } | |
| // Prints a JSON representation of the benchmark results, in a format compatible | |
| // with the github benchmark action. | |
| class JsonEmitter implements ScoreEmitter { | |
| JsonEmitter(this._baseline); | |
| final double _baseline; | |
| final _results = <String, double>{}; | |
| @override | |
| void emit(String testName, double value) { | |
| _results[testName] = value; | |
| } | |
| String write() => | |
| '[${_results.entries.map((entry) => """{ | |
| "name": "${entry.key}", | |
| "unit": "times slower", | |
| "value": ${(entry.value / _baseline).toStringAsFixed(2)} | |
| }""").join(',\n')}]'; | |
| } | |
| Future<void> runBenchmark(CoverageBenchmark benchmark) async { | |
| for (var i = 0; i < 3; ++i) { | |
| try { | |
| await benchmark.report().timeout(const Duration(minutes: 2)); | |
| return; | |
| } on TimeoutException { | |
| print('Timed out'); | |
| } | |
| } | |
| print('Timed out too many times. Giving up.'); | |
| exit(127); | |
| } | |
| Future<String> runBenchmarkSet(String name, String script) async { | |
| final captureEmitter = CaptureEmitter(); | |
| await runBenchmark( | |
| CoverageBenchmark(captureEmitter, '$name - no coverage', script), | |
| ); | |
| final benchmarkBaseline = captureEmitter.capturedValue; | |
| final emitter = JsonEmitter(benchmarkBaseline); | |
| await runBenchmark( | |
| CoverageBenchmark( | |
| emitter, | |
| '$name - basic coverage', | |
| script, | |
| gatherCoverage: true, | |
| ), | |
| ); | |
| await runBenchmark( | |
| CoverageBenchmark( | |
| emitter, | |
| '$name - function coverage', | |
| script, | |
| gatherCoverage: true, | |
| functionCoverage: true, | |
| ), | |
| ); | |
| await runBenchmark( | |
| CoverageBenchmark( | |
| emitter, | |
| '$name - branch coverage', | |
| script, | |
| gatherCoverage: true, | |
| branchCoverage: true, | |
| ), | |
| ); | |
| return emitter.write(); | |
| } | |
| Future<void> main() async { | |
| // Assume this script was started from the root coverage directory. Change to | |
| // the benchmark directory. | |
| Directory.current = 'benchmark'; | |
| final result = await runBenchmarkSet('Many isolates', 'many_isolates.dart'); | |
| await File('data/benchmark_result.json').writeAsString(result); | |
| exit(0); | |
| } |