1
0
mirror of https://github.com/dart-lang/sdk synced 2024-07-01 07:14:29 +00:00

[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>
This commit is contained in:
Daco Harkes 2021-05-27 07:54:14 +00:00 committed by commit-bot@chromium.org
parent f00dc3d056
commit b0bfee6627
7 changed files with 824 additions and 2 deletions

View File

@ -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.

View File

@ -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.

View File

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

View File

@ -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 = <String, String>{
'0': '1',
};
final final1 = <String, String>{
'0': '1',
};
const const5 = <String, String>{
'0': '1',
'1': '2',
'2': '3',
'3': '4',
'4': '5',
};
final final5 = <String, String>{
'0': '1',
'1': '2',
'2': '3',
'3': '4',
'4': '5',
};
const const10 = <String, String>{
'0': '1',
'1': '2',
'2': '3',
'3': '4',
'4': '5',
'5': '6',
'6': '7',
'7': '8',
'8': '9',
'9': '10',
};
final final10 = <String, String>{
'0': '1',
'1': '2',
'2': '3',
'3': '4',
'4': '5',
'5': '6',
'6': '7',
'7': '8',
'8': '9',
'9': '10',
};
const const100 = <String, String>{
'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 = <String, String>{
'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',
};

View File

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

View File

@ -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 = <String, String>{
'0': '1',
};
final final1 = <String, String>{
'0': '1',
};
const const5 = <String, String>{
'0': '1',
'1': '2',
'2': '3',
'3': '4',
'4': '5',
};
final final5 = <String, String>{
'0': '1',
'1': '2',
'2': '3',
'3': '4',
'4': '5',
};
const const10 = <String, String>{
'0': '1',
'1': '2',
'2': '3',
'3': '4',
'4': '5',
'5': '6',
'6': '7',
'7': '8',
'8': '9',
'9': '10',
};
final final10 = <String, String>{
'0': '1',
'1': '2',
'2': '3',
'3': '4',
'4': '5',
'5': '6',
'6': '7',
'7': '8',
'8': '9',
'9': '10',
};
const const100 = <String, String>{
'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 = <String, String>{
'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',
};

View File

@ -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 = <String, String>{');
for (int i = 0; i < mapSize; i++) {
buffer.write("'$i': '${i + 1}',");
}
buffer.write('};');
buffer.write('\n\n');
}