blob: d7593f84bba3d210ba4265da742ff97be1333f76 [file] [log] [blame]
// Copyright (c) 2021, 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.
// Benchmark for https://github.com/dart-lang/sdk/issues/45908.
//
// Measures the average time needed for a lookup in Maps.
import 'dart:math';
import 'maps.dart';
abstract class MapLookupBenchmark {
final String name;
const MapLookupBenchmark(this.name);
Map<String, String> get myMap;
// Returns the number of nanoseconds per call.
double measureFor(Duration duration) {
final map = myMap;
// Prevent `sw.elapsedMicroseconds` from dominating with maps with a
// small number of elements.
final int batching = max(1000 ~/ map.length, 1);
int numberOfLookups = 0;
int totalMicroseconds = 0;
final sw = Stopwatch()..start();
final durationInMicroseconds = duration.inMicroseconds;
do {
for (int i = 0; i < batching; i++) {
String? k = '0';
while (k != null) {
k = map[k];
}
numberOfLookups += map.length;
}
totalMicroseconds = sw.elapsedMicroseconds;
} while (totalMicroseconds < durationInMicroseconds);
final int totalNanoseconds = sw.elapsed.inMicroseconds * 1000;
return totalNanoseconds / numberOfLookups;
}
// Runs warmup phase, runs benchmark and reports result.
void report() {
// Warmup for 100 ms.
measureFor(const Duration(milliseconds: 100));
// Run benchmark for 2 seconds.
final double nsPerCall = measureFor(const Duration(seconds: 2));
// Report result.
print('$name(RunTimeRaw): $nsPerCall ns.');
}
}
class Constant1 extends MapLookupBenchmark {
const Constant1() : super('MapLookup.Constant1');
@override
Map<String, String> get myMap => const1;
}
class Final1 extends MapLookupBenchmark {
const Final1() : super('MapLookup.Final1');
@override
Map<String, String> get myMap => final1;
}
class Constant5 extends MapLookupBenchmark {
const Constant5() : super('MapLookup.Constant5');
@override
Map<String, String> get myMap => const5;
}
class Final5 extends MapLookupBenchmark {
const Final5() : super('MapLookup.Final5');
@override
Map<String, String> get myMap => final5;
}
class Constant10 extends MapLookupBenchmark {
const Constant10() : super('MapLookup.Constant10');
@override
Map<String, String> get myMap => const10;
}
class Final10 extends MapLookupBenchmark {
const Final10() : super('MapLookup.Final10');
@override
Map<String, String> get myMap => final10;
}
class Constant100 extends MapLookupBenchmark {
const Constant100() : super('MapLookup.Constant100');
@override
Map<String, String> get myMap => const100;
}
class Final100 extends MapLookupBenchmark {
const Final100() : super('MapLookup.Final100');
@override
Map<String, String> get myMap => final100;
}
void main() {
final benchmarks = [
() => const Constant1(),
() => const Constant5(),
() => const Constant10(),
() => const Constant100(),
() => const Final1(),
() => const Final5(),
() => const Final10(),
() => const Final100(),
];
for (final benchmark in benchmarks) {
benchmark().report();
}
}