blob: 1bd2990bc0c9ad3c32372ef87ce36177ec0ff0bd [file] [log] [blame] [edit]
// 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);
}