dart-sdk/benchmarks/MapLookup/dart/MapLookup.dart
Daco Harkes b0bfee6627 [benchmarks/vm] Add benchmarks for #45908
The implementation of const map literals is based on linear lookups in
an array containing key/value pairs instead of a hash table.

Bug: https://github.com/dart-lang/sdk/issues/45908

Golem CL:
https://chrome-internal-review.googlesource.com/c/golem/+/3852562

Change-Id: If0a980339ee1342c41f9388e0bd7b3615a4ef4e3
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/200188
Commit-Queue: Daco Harkes <dacoharkes@google.com>
Reviewed-by: Jonas Termansen <sortie@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
2021-05-27 07:54:14 +00:00

132 lines
3.2 KiB
Dart

// 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();
}
}