blob: ef6dfb04d588c6dbb140bfffc74bd1199b940d6b [file] [log] [blame]
// Copyright (c) 2019, 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.
// @dart = 2.9
import "dart:convert" show json, utf8;
import "dart:io" show File, gzip;
import "package:kernel/ast.dart" show Component, DartType, Library;
import "package:kernel/class_hierarchy.dart" show ClassHierarchy;
import "package:kernel/core_types.dart" show CoreTypes;
import "package:kernel/target/targets.dart" show NoneTarget, TargetFlags;
import 'package:kernel/testing/type_parser_environment.dart'
show TypeParserEnvironment, parseLibrary;
import "package:kernel/type_environment.dart"
show SubtypeCheckMode, TypeEnvironment;
import "package:front_end/src/api_prototype/compiler_options.dart"
show CompilerOptions;
import "package:front_end/src/base/processed_options.dart"
show ProcessedOptions;
import "package:front_end/src/fasta/builder/class_builder.dart";
import "package:front_end/src/fasta/compiler_context.dart" show CompilerContext;
import "package:front_end/src/fasta/dill/dill_loader.dart" show DillLoader;
import "package:front_end/src/fasta/dill/dill_target.dart" show DillTarget;
import "package:front_end/src/fasta/kernel/kernel_builder.dart"
show ClassHierarchyBuilder;
import "package:front_end/src/fasta/ticker.dart" show Ticker;
class SubtypesBenchmark {
final Library library;
final List<SubtypeCheck> checks;
SubtypesBenchmark(this.library, this.checks);
}
class SubtypeCheck {
final DartType s;
final DartType t;
final bool isSubtype;
SubtypeCheck(this.s, this.t, this.isSubtype);
String toString() {
return (new StringBuffer()
..write(s)
..write(isSubtype ? " <: " : " !<: ")
..write(t))
.toString();
}
}
SubtypesBenchmark parseBenchMark(String source) {
Map<Object, Object> data = json.decode(source);
List<Object> classes = data["classes"];
Uri uri = Uri.parse("dart:core");
TypeParserEnvironment environment = new TypeParserEnvironment(uri, uri);
Library library =
parseLibrary(uri, classes.join("\n"), environment: environment);
List<Object> checks = data["checks"];
List<SubtypeCheck> subtypeChecks = <SubtypeCheck>[];
for (Map<Object, Object> check in checks) {
String kind = check["kind"];
List<Object> arguments = check["arguments"];
String sSource = arguments[0];
String tSource = arguments[1];
if (sSource.contains("?")) continue;
if (tSource.contains("?")) continue;
if (sSource.contains("⊥")) continue;
if (tSource.contains("⊥")) continue;
TypeParserEnvironment localEnvironment = environment;
if (arguments.length > 2) {
List<Object> typeParametersSource = arguments[2];
localEnvironment = environment
.extendWithTypeParameters("${typeParametersSource.join(', ')}");
}
DartType s = localEnvironment.parseType(sSource);
DartType t = localEnvironment.parseType(tSource);
subtypeChecks.add(new SubtypeCheck(s, t, kind == "isSubtype"));
}
return new SubtypesBenchmark(library, subtypeChecks);
}
void performChecks(List<SubtypeCheck> checks, TypeEnvironment environment) {
for (int i = 0; i < checks.length; i++) {
SubtypeCheck check = checks[i];
bool isSubtype = environment.isSubtypeOf(
check.s, check.t, SubtypeCheckMode.ignoringNullabilities);
if (isSubtype != check.isSubtype) {
throw "Check failed: $check";
}
}
}
void performFastaChecks(
List<SubtypeCheck> checks, ClassHierarchyBuilder hierarchy) {
for (int i = 0; i < checks.length; i++) {
SubtypeCheck check = checks[i];
bool isSubtype = hierarchy.types
.isSubtypeOf(check.s, check.t, SubtypeCheckMode.ignoringNullabilities);
if (isSubtype != check.isSubtype) {
throw "Check failed: $check";
}
}
}
Future<void> run(Uri benchmarkInput, String name) async {
const int runs = 50;
final Ticker ticker = new Ticker(isVerbose: false);
Stopwatch kernelWatch = new Stopwatch();
Stopwatch fastaWatch = new Stopwatch();
List<int> bytes = await new File.fromUri(benchmarkInput).readAsBytes();
if (bytes.length > 3) {
if (bytes[0] == 0x1f && bytes[1] == 0x8b && bytes[2] == 0x08) {
bytes = gzip.decode(bytes);
}
}
SubtypesBenchmark bench = parseBenchMark(utf8.decode(bytes));
bytes = null;
ticker.logMs("Parsed benchmark file");
Component c = new Component(libraries: [bench.library]);
CoreTypes coreTypes = new CoreTypes(c);
ClassHierarchy hierarchy = new ClassHierarchy(c, coreTypes);
TypeEnvironment environment = new TypeEnvironment(coreTypes, hierarchy);
final CompilerContext context = new CompilerContext(new ProcessedOptions(
options: new CompilerOptions()
..packagesFileUri = Uri.base.resolve(".packages")));
await context.runInContext<void>((_) async {
DillTarget target = new DillTarget(
ticker,
await context.options.getUriTranslator(),
new NoneTarget(new TargetFlags()));
final DillLoader loader = target.loader;
loader.appendLibraries(c);
await target.buildOutlines();
ClassBuilder objectClass =
loader.coreLibrary.lookupLocalMember("Object", required: true);
ClassHierarchyBuilder hierarchy =
new ClassHierarchyBuilder(objectClass, loader, coreTypes);
for (int i = 0; i < runs; i++) {
kernelWatch.start();
performChecks(bench.checks, environment);
kernelWatch.stop();
fastaWatch.start();
performFastaChecks(bench.checks, hierarchy);
fastaWatch.stop();
if (i == 0) {
print("SubtypeKernel${name}First(RuntimeRaw): "
"${kernelWatch.elapsedMilliseconds} ms");
print("SubtypeFasta${name}First(RuntimeRaw): "
"${fastaWatch.elapsedMilliseconds} ms");
}
}
});
print("SubtypeKernel${name}Avg${runs}(RuntimeRaw): "
"${kernelWatch.elapsedMilliseconds / runs} ms");
print("SubtypeFasta${name}Avg${runs}(RuntimeRaw): "
"${fastaWatch.elapsedMilliseconds / runs} ms");
}
main() => run(Uri.base.resolve("type_checks.json"), "***");