1+ import 'dart:cli' ;
12import 'dart:io' ;
23
3- import 'package:benchmark_harness/benchmark_harness .dart' ;
4+ import 'package:meta/meta .dart' ;
45import 'package:objectbox/objectbox.dart' ;
56
67import 'model.dart' ;
78import 'objectbox.g.dart' ;
89
9- class Benchmark extends BenchmarkBase {
10+ class Benchmark {
11+ final String name;
1012 final int iterations;
13+ final double coefficient;
14+ final watch = Stopwatch ();
15+ final Emitter emitter;
16+
17+ Benchmark (this .name, {this .iterations = 1 , this .coefficient = 1 })
18+ : emitter = Emitter (iterations, coefficient) {
19+ print ('-------------------------------------------------------------' );
20+ print ('$name (iterations): ${Emitter ._format (iterations .toDouble ())}' );
21+ print (
22+ '$name (count): ${Emitter ._format (iterations / coefficient )}' );
23+ // Measure the total time of the test - if it's too high, you should
24+ // decrease the number of iterations. Expected time is between 2 and 3 sec.
25+ watch.start ();
26+ }
1127
12- Benchmark (String name, {int iterations = 1 , double coefficient = 1 })
13- : iterations = iterations,
14- super (name, emitter: Emitter (iterations, coefficient));
28+ // Not measured setup code executed prior to the benchmark runs.
29+ void setup () {}
1530
16- @override
17- void exercise () => run ();
31+ @mustCallSuper
32+ void teardown () {
33+ final color = watch.elapsedMilliseconds > 3000 ? '\x 1B[31m' : '' ;
34+ print ('$name (total time taken): $color ${watch .elapsed .toString ()}\x 1B[0m' );
35+ }
1836
19- @override
20- void run () {
37+ void run () async {
2138 for (var i = 0 ; i < iterations; i++ ) runIteration (i);
2239 }
2340
24- void runIteration (int iteration) {}
41+ void runIteration (int iteration) async {}
42+
43+ // Runs [f] for at least [minimumMillis] milliseconds.
44+ static Future <double > _measureFor (Function f, int minimumMillis) async {
45+ final minimumMicros = minimumMillis * 1000 ;
46+ var iter = 0 ;
47+ final watch = Stopwatch ()..start ();
48+ var elapsed = 0 ;
49+ while (elapsed < minimumMicros) {
50+ await f ();
51+ elapsed = watch.elapsedMicroseconds;
52+ iter++ ;
53+ }
54+ return elapsed / iter;
55+ }
56+
57+ // Measures the score for the benchmark and returns it.
58+ @nonVirtual
59+ Future <double > _measure () async {
60+ setup ();
61+ // Warmup for at least 100ms. Discard result.
62+ await _measureFor (run, 100 );
63+ // Run the benchmark for at least 2000ms.
64+ var result = await _measureFor (run, 2000 );
65+ teardown ();
66+ return result;
67+ }
68+
69+ @nonVirtual
70+ void report () {
71+ emitter.emit (name, waitFor (_measure ()));
72+ }
2573}
2674
27- class Emitter implements ScoreEmitter {
75+ class Emitter {
2876 static const usInSec = 1000000 ;
2977
3078 final int iterations;
3179 final double coefficient;
3280
3381 const Emitter (this .iterations, this .coefficient);
3482
35- @override
3683 void emit (String testName, double value) {
3784 final timePerIter = value / iterations;
3885 final timePerUnit = timePerIter * coefficient;
39- print ('$testName (Single iteration): ${format (timePerIter )} us' );
40- print ('$testName (Runtime per unit): ${format (timePerUnit )} us' );
41- print ('$testName (Runs per second): ${format (usInSec / timePerIter )}' );
42- print ('$testName (Units per second): ${format (usInSec / timePerUnit )}' );
86+ print ('$testName (Single iteration): ${_format (timePerIter )} us' );
87+ print ('$testName (Runtime per unit): ${_format (timePerUnit )} us' );
88+ print ('$testName (Runs per second): ${_format (usInSec / timePerIter )}' );
89+ print ('$testName (Units per second): ${_format (usInSec / timePerUnit )}' );
4390 }
4491
4592 // Simple number formatting, maybe use a lib?
4693 // * the smaller the number, the more decimal places it has (one up to four).
4794 // * large numbers use thousands separator (defaults to non-breaking space).
48- String format (double num , [String thousandsSeparator = ' ' ]) {
95+ static String _format (double num , [String thousandsSeparator = ' ' ]) {
4996 final decimalPoints = num < 1
5097 ? 4
5198 : num < 10
@@ -72,18 +119,24 @@ class Emitter implements ScoreEmitter {
72119
73120class DbBenchmark extends Benchmark {
74121 static final String dbDir = 'benchmark-db' ;
75- final Store store;
122+ late final Store store;
76123 late final Box <TestEntity > box;
77124
78125 DbBenchmark (String name, {int iterations = 1 , double coefficient = 1 })
79- : store = Store (getObjectBoxModel (), directory: dbDir),
80- super (name, iterations: iterations, coefficient: coefficient) {
126+ : super (name, iterations: iterations, coefficient: coefficient) {
127+ deleteDbDir ();
128+ store = Store (getObjectBoxModel (), directory: dbDir);
81129 box = Box <TestEntity >(store);
82130 }
83131
84132 @override
85133 void teardown () {
86134 store.close ();
135+ deleteDbDir ();
136+ super .teardown ();
137+ }
138+
139+ void deleteDbDir () {
87140 final dir = Directory (dbDir);
88141 if (dir.existsSync ()) dir.deleteSync (recursive: true );
89142 }
0 commit comments