Skip to content

Commit 090eb85

Browse files
authored
Support multiple benchmarks. (#1375)
Support multiple benchmarks. I'm working on optimizing the new formatter and some optimizations help only certain code. To make sure I'm capturing that correctly, it would be good to have some microbenchmarks that push on specific language features. This reorganizes the benchmark runner to allow it support multiple different benchmark cases. It doesn't add any new ones yet. (Also update copyright year since I renamed the file.)
1 parent 4723a12 commit 090eb85

File tree

5 files changed

+98
-76
lines changed

5 files changed

+98
-76
lines changed

benchmark/benchmark.dart

Lines changed: 0 additions & 75 deletions
This file was deleted.
File renamed without changes.
File renamed without changes.

benchmark/before.dart.txt renamed to benchmark/case/large.unit

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1039,4 +1039,4 @@ void _validateSdkConstraint(Pubspec pubspec) {
10391039
pubspec.name,
10401040
'Package ${pubspec.name} requires SDK version '
10411041
'${pubspec.environment.sdkVersion} but the current SDK is ' '${sdk.version}.');
1042-
}
1042+
}

benchmark/run.dart

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// Copyright (c) 2024, 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:io';
6+
7+
import 'package:dart_style/dart_style.dart';
8+
import 'package:dart_style/src/constants.dart';
9+
import 'package:path/path.dart' as p;
10+
11+
const _totalTrials = 100;
12+
const _formatsPerTrial = 10;
13+
14+
final _benchmarkDirectory = p.dirname(p.fromUri(Platform.script));
15+
16+
void main(List<String> args) {
17+
args = args.toList();
18+
var isShort = args.remove('--short');
19+
20+
var benchmarkPath = '';
21+
switch (args) {
22+
case []:
23+
// Default to the large benchmark.
24+
benchmarkPath = p.join(_benchmarkDirectory, 'case/large.unit');
25+
case [var path]:
26+
benchmarkPath = path;
27+
default:
28+
stderr.writeln('Usage: benchmark/run.dart [--short] <path to benchmark>');
29+
exit(64);
30+
}
31+
32+
var sourceLines = File(benchmarkPath).readAsLinesSync();
33+
34+
// The first line may have a "|" to indicate the page width.
35+
var pageWidth = 80;
36+
if (sourceLines[0].endsWith('|')) {
37+
pageWidth = sourceLines[0].indexOf('|');
38+
sourceLines.removeAt(0);
39+
}
40+
41+
var source = sourceLines.join('\n');
42+
43+
var expected =
44+
File(p.setExtension(benchmarkPath, isShort ? '.expect_short' : '.expect'))
45+
.readAsStringSync();
46+
47+
var benchmarkName = p.basenameWithoutExtension(benchmarkPath);
48+
var formatter = DartFormatter(
49+
pageWidth: pageWidth,
50+
experimentFlags: [if (!isShort) tallStyleExperimentFlag]);
51+
var isStatement = benchmarkPath.endsWith('.stmt');
52+
53+
print('Benchmarking "$benchmarkName" '
54+
'using ${isShort ? 'short' : 'tall'} style...');
55+
56+
// Run the benchmark several times. This ensures the VM is warmed up and lets
57+
// us see how much variance there is.
58+
var best = 99999999.0;
59+
for (var i = 0; i <= _totalTrials; i++) {
60+
var stopwatch = Stopwatch()..start();
61+
62+
// For a single benchmark, format the source multiple times.
63+
String? result;
64+
for (var j = 0; j < _formatsPerTrial; j++) {
65+
if (isStatement) {
66+
result = formatter.formatStatement(source);
67+
} else {
68+
result = formatter.format(source);
69+
}
70+
}
71+
72+
var elapsed = stopwatch.elapsedMilliseconds / _formatsPerTrial;
73+
74+
// Keep track of the best run so far.
75+
if (elapsed >= best) continue;
76+
best = elapsed;
77+
78+
// Sanity check to make sure the output is what we expect and to make sure
79+
// the VM doesn't optimize "dead" code away.
80+
if (result != expected) {
81+
print('Incorrect output:\n$result');
82+
exit(1);
83+
}
84+
85+
// Don't print the first run. It's always terrible since the VM hasn't
86+
// warmed up yet.
87+
if (i == 0) continue;
88+
_printResult("Run ${'#$i'.padLeft(4)}", elapsed);
89+
}
90+
91+
_printResult('Best ', best);
92+
}
93+
94+
void _printResult(String label, double time) {
95+
print('$label: ${time.toStringAsFixed(2).padLeft(6)}ms '
96+
"${'=' * ((time * 5).toInt())}");
97+
}

0 commit comments

Comments
 (0)