Skip to content

Commit c74635e

Browse files
authored
Merge pull request #688 from dart-lang/merge-benchmark_harness-package
Merge `package:benchmark_harness`
2 parents 411d26d + ba527fc commit c74635e

21 files changed

+858
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
name: "package:benchmark_harness"
3+
about: "Create a bug or file a feature request against package:benchmark_harness."
4+
labels: "package:benchmark_harness"
5+
---

.github/labeler.yml

+4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
- changed-files:
99
- any-glob-to-any-file: 'pkgs/bazel_worker/**'
1010

11+
'package:benchmark_harness':
12+
- changed-files:
13+
- any-glob-to-any-file: 'pkgs/benchmark_harness/**'
14+
1115
'package:boolean_selector':
1216
- changed-files:
1317
- any-glob-to-any-file: 'pkgs/boolean_selector/**'
+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
name: package:benchmark_harness
2+
3+
on:
4+
# Run on PRs and pushes to the default branch.
5+
push:
6+
branches: [ main ]
7+
paths:
8+
- '.github/workflows/benchmark_harness.yml'
9+
- 'pkgs/benchmark_harness/**'
10+
pull_request:
11+
branches: [ main ]
12+
paths:
13+
- '.github/workflows/benchmark_harness.yml'
14+
- 'pkgs/benchmark_harness/**'
15+
schedule:
16+
- cron: "0 0 * * 0"
17+
18+
env:
19+
PUB_ENVIRONMENT: bot.github
20+
21+
defaults:
22+
run:
23+
working-directory: pkgs/benchmark_harness/
24+
25+
jobs:
26+
# Check code formatting and static analysis on a single OS (linux)
27+
# against Dart dev.
28+
analyze:
29+
runs-on: ubuntu-latest
30+
strategy:
31+
fail-fast: false
32+
matrix:
33+
sdk: [dev]
34+
steps:
35+
- uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938
36+
- uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672
37+
with:
38+
sdk: ${{ matrix.sdk }}
39+
- id: install
40+
name: Install dependencies
41+
run: dart pub get
42+
- name: Check formatting
43+
run: dart format --output=none --set-exit-if-changed .
44+
if: always() && steps.install.outcome == 'success'
45+
- name: Analyze code
46+
run: dart analyze --fatal-infos
47+
if: always() && steps.install.outcome == 'success'
48+
49+
# Run tests on a matrix consisting of two dimensions:
50+
# 1. OS: ubuntu-latest, (macos-latest, windows-latest)
51+
# 2. release channel: dev
52+
test:
53+
needs: analyze
54+
runs-on: ${{ matrix.os }}
55+
strategy:
56+
fail-fast: false
57+
matrix:
58+
# Add macos-latest and/or windows-latest if relevant for this package.
59+
os: [ubuntu-latest]
60+
sdk: [3.2, dev]
61+
steps:
62+
- uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938
63+
- uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672
64+
with:
65+
sdk: ${{ matrix.sdk }}
66+
- id: install
67+
name: Install dependencies
68+
run: dart pub get
69+
- name: Run VM tests
70+
run: dart test --platform vm
71+
if: always() && steps.install.outcome == 'success'
72+
- name: Run Chrome tests
73+
run: dart test --platform chrome
74+
if: always() && steps.install.outcome == 'success'

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ don't naturally belong to other topic monorepos (like
1515
| Package | Description | Version |
1616
| --- | --- | --- |
1717
| [bazel_worker](pkgs/bazel_worker/) | Protocol and utilities to implement or invoke persistent bazel workers. | [![pub package](https://img.shields.io/pub/v/bazel_worker.svg)](https://pub.dev/packages/bazel_worker) |
18+
| [benchmark_harness](pkgs/benchmark_harness/) | The official Dart project benchmark harness. | [![pub package](https://img.shields.io/pub/v/benchmark_harness.svg)](https://pub.dev/packages/benchmark_harness) |
1819
| [boolean_selector](pkgs/boolean_selector/) | A flexible syntax for boolean expressions, based on a simplified version of Dart's expression syntax. | [![pub package](https://img.shields.io/pub/v/boolean_selector.svg)](https://pub.dev/packages/boolean_selector) |
1920
| [browser_launcher](pkgs/browser_launcher/) | Provides a standardized way to launch web browsers for testing and tools. | [![pub package](https://img.shields.io/pub/v/browser_launcher.svg)](https://pub.dev/packages/browser_launcher) |
2021
| [cli_config](pkgs/cli_config/) | A library to take config values from configuration files, CLI arguments, and environment variables. | [![pub package](https://img.shields.io/pub/v/cli_config.svg)](https://pub.dev/packages/cli_config) |

pkgs/benchmark_harness/.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.dart_tool
2+
.packages
3+
.pub
4+
pubspec.lock

pkgs/benchmark_harness/CHANGELOG.md

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
## 2.3.1
2+
3+
- Move to `dart-lang/tools` monorepo.
4+
5+
## 2.3.0
6+
7+
- Require Dart 3.2.
8+
- Add ScoreEmitterV2 interface, documented with the intention to change
9+
ScoreEmitter interface to match it in the next major release,
10+
a breaking change.
11+
- Add `PerfBenchmarkBase` class which runs the 'perf stat' command from
12+
linux-tools on a benchmark and reports metrics from the hardware
13+
performance counters and the iteration count, as well as the run time
14+
measurement reported by `BenchmarkBase`.
15+
16+
## 2.2.2
17+
18+
- Added package topics to the pubspec file.
19+
- Require Dart 2.19.
20+
21+
## 2.2.1
22+
23+
- Improve convergence speed of `BenchmarkBase` measuring algorithm by allowing
24+
some degree of measuring jitter.
25+
26+
## 2.2.0
27+
28+
- Change measuring algorithm in `BenchmarkBase` to avoid calling stopwatch
29+
methods repeatedly in the measuring loop. This makes measurement work better
30+
for `run` methods which are small themselves.
31+
32+
## 2.1.0
33+
34+
- Add AsyncBenchmarkBase.
35+
36+
## 2.0.0
37+
38+
- Stable null safety release.
39+
40+
## 2.0.0-nullsafety.0
41+
42+
- Opt in to null safety.
43+
44+
## 1.0.6
45+
46+
- Require at least Dart 2.1.
47+
48+
## 1.0.5
49+
50+
- Updates to support Dart 2.

pkgs/benchmark_harness/LICENSE

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
Copyright 2021, the Dart project authors.
2+
3+
Redistribution and use in source and binary forms, with or without
4+
modification, are permitted provided that the following conditions are
5+
met:
6+
* Redistributions of source code must retain the above copyright
7+
notice, this list of conditions and the following disclaimer.
8+
* Redistributions in binary form must reproduce the above
9+
copyright notice, this list of conditions and the following
10+
disclaimer in the documentation and/or other materials provided
11+
with the distribution.
12+
* Neither the name of Google LLC nor the names of its
13+
contributors may be used to endorse or promote products derived
14+
from this software without specific prior written permission.
15+
16+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

pkgs/benchmark_harness/README.md

+116
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
[![Build Status](https://github.com/dart-lang/tools/actions/workflows/benchmark_harness.yaml/badge.svg)](https://github.com/dart-lang/tools/actions/workflows/benchmark_harness.yaml)
2+
[![pub package](https://img.shields.io/pub/v/benchmark_harness.svg)](https://pub.dev/packages/benchmark_harness)
3+
[![package publisher](https://img.shields.io/pub/publisher/benchmark_harness.svg)](https://pub.dev/packages/benchmark_harness/publisher)
4+
5+
The Dart project benchmark harness is the recommended starting point when
6+
building a benchmark for Dart.
7+
8+
## Interpreting Results
9+
10+
By default, the reported runtime in `BenchmarkBase` is not for a single call to
11+
`run()`, but for the average time it takes to call `run()` __10 times__ for
12+
legacy reasons. The benchmark harness executes a 10-call timing loop repeatedly
13+
until 2 seconds have elapsed; the reported result is the average of the runtimes
14+
for each loop. This behavior will change in a future major version.
15+
16+
Benchmarks extending `BenchmarkBase` can opt into the reporting the average time
17+
to call `run()` once by overriding the `exercise` method:
18+
19+
```dart
20+
@override
21+
void exercise() => run();
22+
```
23+
24+
`AsyncBenchmarkBase` already reports the average time to call `run()` __once__.
25+
26+
## Comparing Results
27+
28+
If you are running the same benchmark, on the same machine, running the same OS,
29+
the reported run times can be carefully compared across runs.
30+
Carefully because there are a variety of factors which
31+
could cause error in the run time, for example, the load from
32+
other applications running on your machine could alter the result.
33+
34+
Comparing the run time of different benchmarks is not recommended.
35+
In other words, don't compare apples with oranges.
36+
37+
## Features
38+
39+
* `BenchmarkBase` class that all new benchmarks should `extend`.
40+
* `AsyncBenchmarkBase` for asynchronous benchmarks.
41+
* Template benchmark that you can copy and paste when building new benchmarks.
42+
43+
## Getting Started
44+
45+
1\. Add the following to your project's **pubspec.yaml**
46+
47+
```yaml
48+
dependencies:
49+
benchmark_harness: any
50+
```
51+
52+
2\. Install pub packages
53+
54+
```sh
55+
dart pub install
56+
```
57+
58+
3\. Add the following import:
59+
60+
```dart
61+
import 'package:benchmark_harness/benchmark_harness.dart';
62+
```
63+
64+
4\. Create a benchmark class which inherits from `BenchmarkBase` or
65+
`AsyncBenchmarkBase`.
66+
67+
## Example
68+
69+
Create a dart file in the
70+
[`benchmark/`](https://dart.dev/tools/pub/package-layout#tests-and-benchmarks)
71+
folder of your package.
72+
73+
```dart
74+
// Import BenchmarkBase class.
75+
import 'package:benchmark_harness/benchmark_harness.dart';
76+
77+
// Create a new benchmark by extending BenchmarkBase
78+
class TemplateBenchmark extends BenchmarkBase {
79+
const TemplateBenchmark() : super('Template');
80+
81+
static void main() {
82+
const TemplateBenchmark().report();
83+
}
84+
85+
// The benchmark code.
86+
@override
87+
void run() {}
88+
89+
// Not measured setup code executed prior to the benchmark runs.
90+
@override
91+
void setup() {}
92+
93+
// Not measured teardown code executed after the benchmark runs.
94+
@override
95+
void teardown() {}
96+
97+
// To opt into the reporting the time per run() instead of per 10 run() calls.
98+
//@override
99+
//void exercise() => run();
100+
}
101+
102+
void main() {
103+
// Run TemplateBenchmark
104+
TemplateBenchmark.main();
105+
}
106+
```
107+
108+
### Output
109+
110+
```console
111+
Template(RunTime): 0.1568472448997197 us.
112+
```
113+
114+
This is the average amount of time it takes to run `run()` 10 times for
115+
`BenchmarkBase` and once for `AsyncBenchmarkBase`.
116+
> µs is an abbreviation for microseconds.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
include: package:dart_flutter_team_lints/analysis_options.yaml
2+
3+
analyzer:
4+
language:
5+
strict-inference: true
6+
strict-casts: true
7+
8+
linter:
9+
rules:
10+
- avoid_unused_constructor_parameters
11+
- cancel_subscriptions
12+
- literal_only_boolean_expressions
13+
- no_adjacent_strings_in_list
14+
- unnecessary_await_in_return
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright (c) 2021, 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 BenchmarkBase class.
6+
import 'package:benchmark_harness/benchmark_harness.dart';
7+
8+
// Create a new benchmark by extending BenchmarkBase
9+
class TemplateBenchmark extends BenchmarkBase {
10+
const TemplateBenchmark() : super('Template');
11+
12+
static void main() {
13+
const TemplateBenchmark().report();
14+
}
15+
16+
// The benchmark code.
17+
@override
18+
void run() {}
19+
20+
// Not measured setup code executed prior to the benchmark runs.
21+
@override
22+
void setup() {}
23+
24+
// Not measures teardown code executed after the benchmark runs.
25+
@override
26+
void teardown() {}
27+
28+
// To opt into the reporting the time per run() instead of per 10 run() calls.
29+
//@override
30+
//void exercise() => run();
31+
}
32+
33+
void main() {
34+
// Run TemplateBenchmark
35+
TemplateBenchmark.main();
36+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright 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 'package:benchmark_harness/perf_benchmark_harness.dart';
6+
import 'package:test/test.dart';
7+
8+
class PerfBenchmark extends PerfBenchmarkBase {
9+
PerfBenchmark(super.name);
10+
int runCount = 0;
11+
12+
@override
13+
void run() {
14+
runCount++;
15+
for (final i in List.filled(1000, 7)) {
16+
runCount += i - i;
17+
}
18+
}
19+
}
20+
21+
void main() {
22+
test('run is called', () async {
23+
final benchmark = PerfBenchmark('ForLoop');
24+
await benchmark.reportPerf();
25+
});
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Copyright (c) 2021, 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+
export 'src/async_benchmark_base.dart';
6+
export 'src/benchmark_base.dart' show BenchmarkBase;
7+
export 'src/score_emitter.dart';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
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+
export 'src/perf_benchmark_base_stub.dart'
6+
if (dart.library.io) 'src/perf_benchmark_base.dart';
7+
export 'src/score_emitter.dart';

0 commit comments

Comments
 (0)