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