mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 08:24:39 +00:00
![Tess Strickland](/assets/img/avatar_default.png)
Change-Id: I7a169b8c865d88c70e25b8ea5349332968cd9c81 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/300241 Reviewed-by: Daco Harkes <dacoharkes@google.com> Commit-Queue: Tess Strickland <sstrickl@google.com>
158 lines
4 KiB
Dart
158 lines
4 KiB
Dart
// Copyright (c) 2023, 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.
|
|
//
|
|
// Generates both the dart and dart2 version of this benchmark.
|
|
|
|
import 'dart:io';
|
|
import 'dart:math';
|
|
|
|
import 'package:path/path.dart' as path;
|
|
|
|
const String benchmarkName = 'SubtypeTestCache';
|
|
|
|
const List<int> assertionCounts = [
|
|
1,
|
|
5,
|
|
10,
|
|
25,
|
|
50,
|
|
75,
|
|
100,
|
|
250,
|
|
500,
|
|
750,
|
|
1000
|
|
];
|
|
|
|
void generateBenchmarkClassesAndUtilities(IOSink output) {
|
|
final maxCount = assertionCounts.reduce(max);
|
|
output.writeln('''
|
|
// Copyright (c) 2023, 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.
|
|
//
|
|
// This benchmark suite measures the overhead of looking up elements of
|
|
// SubtypeTestCaches, which are used when a type testing stub cannot determine
|
|
// whether a given type is assignable.
|
|
|
|
import 'package:benchmark_harness/benchmark_harness.dart';
|
|
|
|
void main() {''');
|
|
|
|
// We must run the benchmarks from smallest count to largest, since a single
|
|
// STC is shared across all the benchmarks (due to the single call site in
|
|
// [check]). This ensures that benchmarks that are testing counts small
|
|
// enough for a linear STC use a linear STC.
|
|
final sortedCounts = assertionCounts.toList(growable: false);
|
|
sortedCounts.sort();
|
|
for (final count in sortedCounts) {
|
|
output.write('''
|
|
const STC$count().report();
|
|
''');
|
|
}
|
|
// We need to run the STCSame<max> benchmark only after running all the
|
|
// STC<count> benchmarks, so that we ensure the shared STC is properly primed.
|
|
output.write('''
|
|
const STCSame$maxCount().report();
|
|
''');
|
|
output.writeln('''
|
|
}
|
|
|
|
class STCBenchmarkBase extends BenchmarkBase {
|
|
final int count;
|
|
const STCBenchmarkBase(String name, this.count) : super(name);
|
|
|
|
// Normalize the cost across the benchmarks by number of type tests.
|
|
@override
|
|
void report() => emitter.emit(name, measure() / count);
|
|
}
|
|
''');
|
|
|
|
for (final count in assertionCounts) {
|
|
output.write('''
|
|
class STC$count extends STCBenchmarkBase {
|
|
const STC$count() : super('$benchmarkName.STC$count', $count);
|
|
|
|
@override
|
|
void run() {
|
|
''');
|
|
|
|
for (int i = 0; i < count; i++) {
|
|
output.write('''
|
|
check<int>(instances[$i]);
|
|
''');
|
|
}
|
|
|
|
output.writeln('''
|
|
}
|
|
}
|
|
''');
|
|
}
|
|
|
|
output.write('''
|
|
class STCSame$maxCount extends STCBenchmarkBase {
|
|
const STCSame$maxCount() : super('$benchmarkName.STCSame$maxCount', $maxCount);
|
|
|
|
@override
|
|
void run() {
|
|
// Do $maxCount AssertAssignable checks for the last type checked in the
|
|
// STC$maxCount benchmark.
|
|
''');
|
|
|
|
for (int i = 0; i < maxCount; i++) {
|
|
output.write('''
|
|
check<int>(instances[${maxCount - 1}]);
|
|
''');
|
|
}
|
|
|
|
output.writeln('''
|
|
}
|
|
}
|
|
|
|
@pragma('vm:never-inline')
|
|
@pragma('dart2js:never-inline')
|
|
void check<S>(dynamic s) => s as C<S> Function();
|
|
|
|
class C<T> {}
|
|
''');
|
|
|
|
for (int i = 0; i < maxCount; i++) {
|
|
output.write('''
|
|
class C$i<T> extends C<T> {}
|
|
|
|
C$i<S> closure$i<S>() => C$i<S>();
|
|
|
|
''');
|
|
}
|
|
|
|
// We create constant tearoffs of the closures above to use for our values
|
|
// in the `as` checks. We could make constant instances of the classes, but
|
|
// the specialized TTS for the `C` class hierarchy means that we'll never
|
|
// actually hit the SubtypeTestCache!
|
|
//
|
|
// Using closures both avoids the likelihood of eventually optimizing the TTS
|
|
// for this check and making this benchmark outdated and also ensures the VM
|
|
// performs the most intensive check for each STC entry, i.e., the
|
|
// Subtype7TestCache stub is called.
|
|
output.write('''
|
|
const instances = <dynamic>[
|
|
''');
|
|
for (int i = 0; i < maxCount; i++) {
|
|
output.write('''
|
|
closure$i<int>,
|
|
''');
|
|
}
|
|
output.write('''
|
|
];
|
|
''');
|
|
}
|
|
|
|
void main() {
|
|
final dartFilePath = path.join(
|
|
path.dirname(Platform.script.path), 'dart', '$benchmarkName.dart');
|
|
final dartSink = File(dartFilePath).openWrite();
|
|
generateBenchmarkClassesAndUtilities(dartSink);
|
|
dartSink..flush();
|
|
}
|