@@ -15,24 +15,39 @@ import 'utils.dart';
1515
1616/// Runs the DevTools web benchmarks and reports the benchmark data.
1717///
18- /// Arguments:
19- /// * --browser - runs the benchmark tests in the browser (non-headless mode)
20- /// * --wasm - runs the benchmark tests with the dart2wasm compiler
21- ///
22- /// See [BenchmarkArgs] .
18+ /// To see available arguments, run this script with the `-h` flag.
2319Future <void > main (List <String > args) async {
20+ if (args.isNotEmpty && args.first == '-h' ) {
21+ stdout.writeln (BenchmarkArgs ._buildArgParser ().usage);
22+ return ;
23+ }
24+
2425 final benchmarkArgs = BenchmarkArgs (args);
26+ final benchmarkResults = < BenchmarkResults > [];
27+ for (var i = 0 ; i < benchmarkArgs.averageOf; i++ ) {
28+ stdout.writeln ('Starting web benchmark tests (run #$i ) ...' );
29+ benchmarkResults.add (
30+ await serveWebBenchmark (
31+ benchmarkAppDirectory: projectRootDirectory (),
32+ entryPoint: 'benchmark/test_infra/client.dart' ,
33+ compilationOptions: CompilationOptions (useWasm: benchmarkArgs.useWasm),
34+ treeShakeIcons: false ,
35+ initialPage: benchmarkInitialPage,
36+ headless: ! benchmarkArgs.useBrowser,
37+ ),
38+ );
39+ stdout.writeln ('Web benchmark tests finished (run #$i ).' );
40+ }
2541
26- stdout.writeln ('Starting web benchmark tests...' );
27- final taskResult = await serveWebBenchmark (
28- benchmarkAppDirectory: projectRootDirectory (),
29- entryPoint: 'benchmark/test_infra/client.dart' ,
30- compilationOptions: CompilationOptions (useWasm: benchmarkArgs.useWasm),
31- treeShakeIcons: false ,
32- initialPage: benchmarkInitialPage,
33- headless: ! benchmarkArgs.useBrowser,
34- );
35- stdout.writeln ('Web benchmark tests finished.' );
42+ late final BenchmarkResults taskResult;
43+ if (benchmarkArgs.averageOf == 1 ) {
44+ taskResult = benchmarkResults.first;
45+ } else {
46+ stdout.writeln (
47+ 'Taking the average of ${benchmarkResults .length } benchmark runs.' ,
48+ );
49+ taskResult = averageBenchmarkResults (benchmarkResults);
50+ }
3651
3752 final resultsAsMap = taskResult.toJson ();
3853 final resultsAsJsonString =
@@ -84,6 +99,8 @@ class BenchmarkArgs {
8499
85100 bool get useWasm => argResults[_wasmFlag];
86101
102+ int get averageOf => int .parse (argResults[_averageOfOption]);
103+
87104 String ? get saveToFileLocation => argResults[_saveToFileOption];
88105
89106 String ? get baselineLocation => argResults[_baselineOption];
@@ -96,15 +113,19 @@ class BenchmarkArgs {
96113
97114 static const _baselineOption = 'baseline' ;
98115
116+ static const _averageOfOption = 'average-of' ;
117+
99118 /// Builds an arg parser for DevTools benchmarks.
100119 static ArgParser _buildArgParser () {
101120 return ArgParser ()
102121 ..addFlag (
103122 _browserFlag,
123+ negatable: false ,
104124 help: 'Runs the benchmark tests in browser mode (not headless mode).' ,
105125 )
106126 ..addFlag (
107127 _wasmFlag,
128+ negatable: false ,
108129 help: 'Runs the benchmark tests with dart2wasm' ,
109130 )
110131 ..addOption (
@@ -118,6 +139,44 @@ class BenchmarkArgs {
118139 'baseline file should be created by running this script with the '
119140 '$_saveToFileOption in a separate test run.' ,
120141 valueHelp: '/Users/me/Downloads/baseline.json' ,
142+ )
143+ ..addOption (
144+ _averageOfOption,
145+ defaultsTo: '1' ,
146+ help: 'The number of times to run the benchmark. The returned results '
147+ 'will be the average of all the benchmark runs when this value is '
148+ 'greater than 1.' ,
149+ valueHelp: '5' ,
121150 );
122151 }
123152}
153+
154+ // TODO(kenz): upstream the logic to average benchmarks into the
155+ // package:web_benchmarks
156+
157+ /// Returns the average of the benchmark results in [results] .
158+ ///
159+ /// Each element in [results] is expected to have identical benchmark names and
160+ /// metrics; otherwise, an [Exception] will be thrown.
161+ BenchmarkResults averageBenchmarkResults (List <BenchmarkResults > results) {
162+ if (results.isEmpty) {
163+ throw Exception ('Cannot take average of empty list.' );
164+ }
165+
166+ var totalSum = results.first;
167+ for (int i = 1 ; i < results.length; i++ ) {
168+ final current = results[i];
169+ totalSum = totalSum.sumWith (current);
170+ }
171+
172+ final average = totalSum.toJson ();
173+ for (final benchmark in totalSum.scores.keys) {
174+ final scoresForBenchmark = totalSum.scores[benchmark]! ;
175+ for (int i = 0 ; i < scoresForBenchmark.length; i++ ) {
176+ final score = scoresForBenchmark[i];
177+ final averageValue = score.value / results.length;
178+ average[benchmark]! [i]['value' ] = averageValue;
179+ }
180+ }
181+ return BenchmarkResults .parse (average);
182+ }
0 commit comments