diff --git a/benchmarks/Calls/dart/Calls.dart b/benchmarks/Calls/dart/Calls.dart index 5b94b2a56de..ae546633c91 100644 --- a/benchmarks/Calls/dart/Calls.dart +++ b/benchmarks/Calls/dart/Calls.dart @@ -816,7 +816,7 @@ class SyncCallBenchmark { // Runs warmup phase, runs benchmark and reports result. void report() { - // Warmup for 200 ms. + // Warmup for 100 ms. measureFor(const Duration(milliseconds: 100)); // Run benchmark for 2 seconds. diff --git a/benchmarks/Calls/dart2/Calls.dart b/benchmarks/Calls/dart2/Calls.dart index 32cc0dd7da1..e1d07c9cd09 100644 --- a/benchmarks/Calls/dart2/Calls.dart +++ b/benchmarks/Calls/dart2/Calls.dart @@ -818,7 +818,7 @@ class SyncCallBenchmark { // Runs warmup phase, runs benchmark and reports result. void report() { - // Warmup for 200 ms. + // Warmup for 100 ms. measureFor(const Duration(milliseconds: 100)); // Run benchmark for 2 seconds. diff --git a/benchmarks/MapLookup/dart/MapLookup.dart b/benchmarks/MapLookup/dart/MapLookup.dart new file mode 100644 index 00000000000..d7593f84bba --- /dev/null +++ b/benchmarks/MapLookup/dart/MapLookup.dart @@ -0,0 +1,131 @@ +// 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 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 get myMap => const1; +} + +class Final1 extends MapLookupBenchmark { + const Final1() : super('MapLookup.Final1'); + + @override + Map get myMap => final1; +} + +class Constant5 extends MapLookupBenchmark { + const Constant5() : super('MapLookup.Constant5'); + + @override + Map get myMap => const5; +} + +class Final5 extends MapLookupBenchmark { + const Final5() : super('MapLookup.Final5'); + + @override + Map get myMap => final5; +} + +class Constant10 extends MapLookupBenchmark { + const Constant10() : super('MapLookup.Constant10'); + + @override + Map get myMap => const10; +} + +class Final10 extends MapLookupBenchmark { + const Final10() : super('MapLookup.Final10'); + + @override + Map get myMap => final10; +} + +class Constant100 extends MapLookupBenchmark { + const Constant100() : super('MapLookup.Constant100'); + + @override + Map get myMap => const100; +} + +class Final100 extends MapLookupBenchmark { + const Final100() : super('MapLookup.Final100'); + + @override + Map 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(); + } +} diff --git a/benchmarks/MapLookup/dart/maps.dart b/benchmarks/MapLookup/dart/maps.dart new file mode 100644 index 00000000000..0817b178146 --- /dev/null +++ b/benchmarks/MapLookup/dart/maps.dart @@ -0,0 +1,259 @@ +// 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. + +const const1 = { + '0': '1', +}; + +final final1 = { + '0': '1', +}; + +const const5 = { + '0': '1', + '1': '2', + '2': '3', + '3': '4', + '4': '5', +}; + +final final5 = { + '0': '1', + '1': '2', + '2': '3', + '3': '4', + '4': '5', +}; + +const const10 = { + '0': '1', + '1': '2', + '2': '3', + '3': '4', + '4': '5', + '5': '6', + '6': '7', + '7': '8', + '8': '9', + '9': '10', +}; + +final final10 = { + '0': '1', + '1': '2', + '2': '3', + '3': '4', + '4': '5', + '5': '6', + '6': '7', + '7': '8', + '8': '9', + '9': '10', +}; + +const const100 = { + '0': '1', + '1': '2', + '2': '3', + '3': '4', + '4': '5', + '5': '6', + '6': '7', + '7': '8', + '8': '9', + '9': '10', + '10': '11', + '11': '12', + '12': '13', + '13': '14', + '14': '15', + '15': '16', + '16': '17', + '17': '18', + '18': '19', + '19': '20', + '20': '21', + '21': '22', + '22': '23', + '23': '24', + '24': '25', + '25': '26', + '26': '27', + '27': '28', + '28': '29', + '29': '30', + '30': '31', + '31': '32', + '32': '33', + '33': '34', + '34': '35', + '35': '36', + '36': '37', + '37': '38', + '38': '39', + '39': '40', + '40': '41', + '41': '42', + '42': '43', + '43': '44', + '44': '45', + '45': '46', + '46': '47', + '47': '48', + '48': '49', + '49': '50', + '50': '51', + '51': '52', + '52': '53', + '53': '54', + '54': '55', + '55': '56', + '56': '57', + '57': '58', + '58': '59', + '59': '60', + '60': '61', + '61': '62', + '62': '63', + '63': '64', + '64': '65', + '65': '66', + '66': '67', + '67': '68', + '68': '69', + '69': '70', + '70': '71', + '71': '72', + '72': '73', + '73': '74', + '74': '75', + '75': '76', + '76': '77', + '77': '78', + '78': '79', + '79': '80', + '80': '81', + '81': '82', + '82': '83', + '83': '84', + '84': '85', + '85': '86', + '86': '87', + '87': '88', + '88': '89', + '89': '90', + '90': '91', + '91': '92', + '92': '93', + '93': '94', + '94': '95', + '95': '96', + '96': '97', + '97': '98', + '98': '99', + '99': '100', +}; + +final final100 = { + '0': '1', + '1': '2', + '2': '3', + '3': '4', + '4': '5', + '5': '6', + '6': '7', + '7': '8', + '8': '9', + '9': '10', + '10': '11', + '11': '12', + '12': '13', + '13': '14', + '14': '15', + '15': '16', + '16': '17', + '17': '18', + '18': '19', + '19': '20', + '20': '21', + '21': '22', + '22': '23', + '23': '24', + '24': '25', + '25': '26', + '26': '27', + '27': '28', + '28': '29', + '29': '30', + '30': '31', + '31': '32', + '32': '33', + '33': '34', + '34': '35', + '35': '36', + '36': '37', + '37': '38', + '38': '39', + '39': '40', + '40': '41', + '41': '42', + '42': '43', + '43': '44', + '44': '45', + '45': '46', + '46': '47', + '47': '48', + '48': '49', + '49': '50', + '50': '51', + '51': '52', + '52': '53', + '53': '54', + '54': '55', + '55': '56', + '56': '57', + '57': '58', + '58': '59', + '59': '60', + '60': '61', + '61': '62', + '62': '63', + '63': '64', + '64': '65', + '65': '66', + '66': '67', + '67': '68', + '68': '69', + '69': '70', + '70': '71', + '71': '72', + '72': '73', + '73': '74', + '74': '75', + '75': '76', + '76': '77', + '77': '78', + '78': '79', + '79': '80', + '80': '81', + '81': '82', + '82': '83', + '83': '84', + '84': '85', + '85': '86', + '86': '87', + '87': '88', + '88': '89', + '89': '90', + '90': '91', + '91': '92', + '92': '93', + '93': '94', + '94': '95', + '95': '96', + '96': '97', + '97': '98', + '98': '99', + '99': '100', +}; diff --git a/benchmarks/MapLookup/dart2/MapLookup.dart b/benchmarks/MapLookup/dart2/MapLookup.dart new file mode 100644 index 00000000000..d7593f84bba --- /dev/null +++ b/benchmarks/MapLookup/dart2/MapLookup.dart @@ -0,0 +1,131 @@ +// 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 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 get myMap => const1; +} + +class Final1 extends MapLookupBenchmark { + const Final1() : super('MapLookup.Final1'); + + @override + Map get myMap => final1; +} + +class Constant5 extends MapLookupBenchmark { + const Constant5() : super('MapLookup.Constant5'); + + @override + Map get myMap => const5; +} + +class Final5 extends MapLookupBenchmark { + const Final5() : super('MapLookup.Final5'); + + @override + Map get myMap => final5; +} + +class Constant10 extends MapLookupBenchmark { + const Constant10() : super('MapLookup.Constant10'); + + @override + Map get myMap => const10; +} + +class Final10 extends MapLookupBenchmark { + const Final10() : super('MapLookup.Final10'); + + @override + Map get myMap => final10; +} + +class Constant100 extends MapLookupBenchmark { + const Constant100() : super('MapLookup.Constant100'); + + @override + Map get myMap => const100; +} + +class Final100 extends MapLookupBenchmark { + const Final100() : super('MapLookup.Final100'); + + @override + Map 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(); + } +} diff --git a/benchmarks/MapLookup/dart2/maps.dart b/benchmarks/MapLookup/dart2/maps.dart new file mode 100644 index 00000000000..0817b178146 --- /dev/null +++ b/benchmarks/MapLookup/dart2/maps.dart @@ -0,0 +1,259 @@ +// 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. + +const const1 = { + '0': '1', +}; + +final final1 = { + '0': '1', +}; + +const const5 = { + '0': '1', + '1': '2', + '2': '3', + '3': '4', + '4': '5', +}; + +final final5 = { + '0': '1', + '1': '2', + '2': '3', + '3': '4', + '4': '5', +}; + +const const10 = { + '0': '1', + '1': '2', + '2': '3', + '3': '4', + '4': '5', + '5': '6', + '6': '7', + '7': '8', + '8': '9', + '9': '10', +}; + +final final10 = { + '0': '1', + '1': '2', + '2': '3', + '3': '4', + '4': '5', + '5': '6', + '6': '7', + '7': '8', + '8': '9', + '9': '10', +}; + +const const100 = { + '0': '1', + '1': '2', + '2': '3', + '3': '4', + '4': '5', + '5': '6', + '6': '7', + '7': '8', + '8': '9', + '9': '10', + '10': '11', + '11': '12', + '12': '13', + '13': '14', + '14': '15', + '15': '16', + '16': '17', + '17': '18', + '18': '19', + '19': '20', + '20': '21', + '21': '22', + '22': '23', + '23': '24', + '24': '25', + '25': '26', + '26': '27', + '27': '28', + '28': '29', + '29': '30', + '30': '31', + '31': '32', + '32': '33', + '33': '34', + '34': '35', + '35': '36', + '36': '37', + '37': '38', + '38': '39', + '39': '40', + '40': '41', + '41': '42', + '42': '43', + '43': '44', + '44': '45', + '45': '46', + '46': '47', + '47': '48', + '48': '49', + '49': '50', + '50': '51', + '51': '52', + '52': '53', + '53': '54', + '54': '55', + '55': '56', + '56': '57', + '57': '58', + '58': '59', + '59': '60', + '60': '61', + '61': '62', + '62': '63', + '63': '64', + '64': '65', + '65': '66', + '66': '67', + '67': '68', + '68': '69', + '69': '70', + '70': '71', + '71': '72', + '72': '73', + '73': '74', + '74': '75', + '75': '76', + '76': '77', + '77': '78', + '78': '79', + '79': '80', + '80': '81', + '81': '82', + '82': '83', + '83': '84', + '84': '85', + '85': '86', + '86': '87', + '87': '88', + '88': '89', + '89': '90', + '90': '91', + '91': '92', + '92': '93', + '93': '94', + '94': '95', + '95': '96', + '96': '97', + '97': '98', + '98': '99', + '99': '100', +}; + +final final100 = { + '0': '1', + '1': '2', + '2': '3', + '3': '4', + '4': '5', + '5': '6', + '6': '7', + '7': '8', + '8': '9', + '9': '10', + '10': '11', + '11': '12', + '12': '13', + '13': '14', + '14': '15', + '15': '16', + '16': '17', + '17': '18', + '18': '19', + '19': '20', + '20': '21', + '21': '22', + '22': '23', + '23': '24', + '24': '25', + '25': '26', + '26': '27', + '27': '28', + '28': '29', + '29': '30', + '30': '31', + '31': '32', + '32': '33', + '33': '34', + '34': '35', + '35': '36', + '36': '37', + '37': '38', + '38': '39', + '39': '40', + '40': '41', + '41': '42', + '42': '43', + '43': '44', + '44': '45', + '45': '46', + '46': '47', + '47': '48', + '48': '49', + '49': '50', + '50': '51', + '51': '52', + '52': '53', + '53': '54', + '54': '55', + '55': '56', + '56': '57', + '57': '58', + '58': '59', + '59': '60', + '60': '61', + '61': '62', + '62': '63', + '63': '64', + '64': '65', + '65': '66', + '66': '67', + '67': '68', + '68': '69', + '69': '70', + '70': '71', + '71': '72', + '72': '73', + '73': '74', + '74': '75', + '75': '76', + '76': '77', + '77': '78', + '78': '79', + '79': '80', + '80': '81', + '81': '82', + '82': '83', + '83': '84', + '84': '85', + '85': '86', + '86': '87', + '87': '88', + '88': '89', + '89': '90', + '90': '91', + '91': '92', + '92': '93', + '93': '94', + '94': '95', + '95': '96', + '96': '97', + '97': '98', + '98': '99', + '99': '100', +}; diff --git a/benchmarks/MapLookup/generate_maps.dart b/benchmarks/MapLookup/generate_maps.dart new file mode 100644 index 00000000000..9086cd03386 --- /dev/null +++ b/benchmarks/MapLookup/generate_maps.dart @@ -0,0 +1,42 @@ +// 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. + +import 'dart:io'; + +void main() { + final buffer = StringBuffer(); + buffer.write(''' +// 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. + + '''); + + generateMap(buffer, 'const1', 1, isConst: true); + generateMap(buffer, 'final1', 1, isConst: false); + generateMap(buffer, 'const5', 5, isConst: true); + generateMap(buffer, 'final5', 5, isConst: false); + generateMap(buffer, 'const10', 10, isConst: true); + generateMap(buffer, 'final10', 10, isConst: false); + generateMap(buffer, 'const100', 100, isConst: true); + generateMap(buffer, 'final100', 100, isConst: false); + + for (final folder in ['dart', 'dart2']) { + final path = Platform.script.resolve('$folder/maps.dart').toFilePath(); + File(path).writeAsStringSync(buffer.toString()); + Process.runSync(Platform.executable, ['format', path]); + print('Generated $path.'); + } +} + +void generateMap(StringBuffer buffer, String name, int mapSize, + {bool isConst = true}) { + final constOrFinal = isConst ? 'const' : 'final'; + buffer.write('$constOrFinal $name = {'); + for (int i = 0; i < mapSize; i++) { + buffer.write("'$i': '${i + 1}',"); + } + buffer.write('};'); + buffer.write('\n\n'); +}