9f9be9d3ea
Change-Id: I1f5834fcf16c1636949492d4d5e529daed68e9db Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/509100 Reviewed-by: Alexander Aprelev <aam@google.com> Commit-Queue: Alexander Aprelev <aam@google.com>
313 lines
8.1 KiB
Dart
313 lines
8.1 KiB
Dart
// Copyright (c) 2024, 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:async";
|
|
import "dart:convert";
|
|
import "dart:io";
|
|
import "dart:io" as io;
|
|
import "dart:math";
|
|
|
|
final buildDirs = [
|
|
"out/ReleaseX64",
|
|
"out/ReleaseX64C",
|
|
"out/ReleaseSIMARM64",
|
|
"out/ReleaseSIMARM64C",
|
|
"out/ReleaseSIMRISCV64",
|
|
"out/DebugX64",
|
|
"out/DebugX64C",
|
|
"out/DebugSIMARM64",
|
|
"out/DebugSIMARM64C",
|
|
"out/DebugSIMRISCV64",
|
|
];
|
|
|
|
final alwaysFlags = ["--no-dds"];
|
|
|
|
final profilerFlags = [
|
|
"--profile_vm=true", // default is different for simulators
|
|
"--profile_vm=false",
|
|
"--profile_period=${range(500, 10000)}",
|
|
"--max_profile_depth=${range(8, 256)}",
|
|
"--sample_buffer_duration=${range(30, 60)}",
|
|
];
|
|
|
|
final gcFlags = [
|
|
"--compactor_tasks=${range(1, 3)}",
|
|
"--dontneed_on_sweep",
|
|
"--force_evacuation",
|
|
"--mark_when_idle",
|
|
"--marker_tasks=${range(1, 3)}",
|
|
"--no_concurrent_mark",
|
|
"--no_concurrent_sweep",
|
|
"--no_inline_alloc",
|
|
"--runtime_allocate_old",
|
|
"--runtime_allocate_spill_tlab",
|
|
"--scavenger_tasks=${range(1, 3)}",
|
|
"--use_compactor",
|
|
"--verify_after_gc",
|
|
"--verify_after_marking",
|
|
"--verify_before_gc",
|
|
"--verify_store_buffer",
|
|
"--write_protect_code",
|
|
"--gc_at_throw",
|
|
];
|
|
|
|
final compilerFlags = [
|
|
"--branch_coverage",
|
|
"--code_comments",
|
|
"--force_clone_compiler_objects",
|
|
"--force_indirect_calls",
|
|
"--force_switch_dispatch_type=${range(0, 2)}",
|
|
"--inlining_callee_call_sites_threshold=${range(1, 3)}",
|
|
"--inlining_callee_size_threshold=${range(100, 300)}",
|
|
"--inlining_caller_size_threshold=${range(10000, 100000)}",
|
|
"--inlining_depth_threshold=${range(2, 8)}",
|
|
"--inlining_hotness=${range(5, 20)}",
|
|
"--inlining_recursion_depth_threshold=${range(0, 3)}",
|
|
"--inlining_size_threshold=${range(15, 35)}",
|
|
"--inlining_small_leaf_size_threshold=${range(40, 60)}",
|
|
"--link_natives_lazily",
|
|
"--max_equality_polymorphic_checks=${range(8, 256)}",
|
|
"--max_polymorphic_checks=${range(4, 12)}",
|
|
"--no_array_bounds_check_elimination",
|
|
"--no_background_compilation",
|
|
"--no_compress_deopt_info",
|
|
"--no_dead_store_elimination",
|
|
"--no_enable_peephole",
|
|
"--no_guess_icdata_cid",
|
|
"--no_intrinsify",
|
|
"--no_load_cse",
|
|
"--no_polymorphic_with_deopt",
|
|
"--no_propagate_ic_data",
|
|
"--no_prune_dead_locals",
|
|
"--no_remove_redundant_phis",
|
|
"--no_reorder_basic_blocks",
|
|
"--no_truncating_left_shift",
|
|
"--no_two_args_smi_icd",
|
|
"--no_unopt_megamorphic_calls",
|
|
"--no_unopt_monomorphic_calls",
|
|
"--no_use_cha_deopt",
|
|
"--no_use_field_guards",
|
|
"--no_use_osr",
|
|
"--no_use_register_cc",
|
|
"--optimization_counter_threshold=${range(1000, 50000)}",
|
|
"--optimization_level=${range(1, 3)}",
|
|
"--target_unknown_cpu",
|
|
"--test_il_serialization",
|
|
"--use_slow_path",
|
|
];
|
|
|
|
final random = new Random();
|
|
int range(int min, int max) {
|
|
return random.nextInt(max - min + 1) + min;
|
|
}
|
|
|
|
String oneOf(List<String> choices) {
|
|
return choices[random.nextInt(choices.length)];
|
|
}
|
|
|
|
List<String> someOf(List<String> choices) {
|
|
var result = <String>[];
|
|
for (var i = 0, n = range(0, 2); i < n; i++) {
|
|
result.add(oneOf(choices));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
List<String> someJitRuntimeFlags() {
|
|
return [
|
|
"--profiler", // Off by default unless VM service enabled
|
|
...someOf(profilerFlags),
|
|
...someOf(gcFlags),
|
|
...someOf(compilerFlags),
|
|
];
|
|
}
|
|
|
|
List<String> someAotRuntimeFlags() {
|
|
return [
|
|
"--profiler", // Off by default unless VM service enabled
|
|
...someOf(profilerFlags),
|
|
...someOf(gcFlags),
|
|
];
|
|
}
|
|
|
|
List<String> someGenSnapshotFlags() {
|
|
return [...someOf(gcFlags), ...someOf(compilerFlags)];
|
|
}
|
|
|
|
Stopwatch stopwatch = new Stopwatch();
|
|
|
|
const overallTimeout = Duration(minutes: 30);
|
|
Duration get remainingTimeout => overallTimeout - stopwatch.elapsed;
|
|
|
|
// LUCI will kill recipe steps if they go 1200 seconds without any output.
|
|
const statusTimeout = Duration(minutes: 5);
|
|
int pendingTaskCount = 0;
|
|
late Timer pendingTimer;
|
|
void taskStart() {
|
|
if (pendingTaskCount++ == 0) {
|
|
pendingTimer = new Timer.periodic(statusTimeout, (timer) {
|
|
print(
|
|
"$pendingTaskCount tasks still running after "
|
|
"${stopwatch.elapsed.inMinutes} minutes",
|
|
);
|
|
});
|
|
}
|
|
}
|
|
|
|
void taskEnd() {
|
|
if (--pendingTaskCount == 0) {
|
|
pendingTimer.cancel();
|
|
}
|
|
}
|
|
|
|
Future<void> test(
|
|
List<String> Function(String) createDartCommand,
|
|
int taskIndex,
|
|
String extension,
|
|
) async {
|
|
taskStart();
|
|
|
|
var dartCommand = createDartCommand("out/dartfuzz/$taskIndex.$extension");
|
|
var dartScript = dartCommand[0];
|
|
var dartArguments = dartCommand.getRange(1, dartCommand.length).toList();
|
|
|
|
var buildDir = oneOf(buildDirs);
|
|
List<List<String>> commands;
|
|
if (random.nextBool()) {
|
|
// JIT
|
|
commands = [
|
|
[
|
|
"$buildDir/dartvm",
|
|
...alwaysFlags,
|
|
...someJitRuntimeFlags(),
|
|
dartScript,
|
|
...dartArguments,
|
|
],
|
|
[
|
|
"diff",
|
|
"out/dartfuzz/expected.$extension",
|
|
"out/dartfuzz/$taskIndex.$extension",
|
|
],
|
|
];
|
|
} else {
|
|
// AOT
|
|
commands = [
|
|
[
|
|
"out/ReleaseX64/dartvm",
|
|
...alwaysFlags,
|
|
"pkg/vm/bin/gen_kernel.dart",
|
|
"--platform=$buildDir/vm_platform.dill",
|
|
"--aot",
|
|
"--output=out/dartfuzz/$taskIndex.dill",
|
|
dartScript,
|
|
],
|
|
[
|
|
"$buildDir/gen_snapshot",
|
|
...someGenSnapshotFlags(),
|
|
"--snapshot_kind=app-aot-elf",
|
|
"--elf=out/dartfuzz/$taskIndex.elf",
|
|
"out/dartfuzz/$taskIndex.dill",
|
|
],
|
|
[
|
|
"$buildDir/dartaotruntime",
|
|
...alwaysFlags,
|
|
...someAotRuntimeFlags(),
|
|
"out/dartfuzz/$taskIndex.elf",
|
|
...dartArguments,
|
|
],
|
|
[
|
|
"diff",
|
|
"out/dartfuzz/expected.$extension",
|
|
"out/dartfuzz/$taskIndex.$extension",
|
|
],
|
|
];
|
|
}
|
|
|
|
for (int commandIndex = 0; commandIndex < commands.length; commandIndex++) {
|
|
var command = commands[commandIndex];
|
|
var executable = command[0];
|
|
var arguments = command.getRange(1, command.length).toList();
|
|
var cmdline = command.join(' ');
|
|
print("Start: $cmdline");
|
|
var timeout = remainingTimeout;
|
|
if (timeout.isNegative) {
|
|
print("Timeout: $cmdline");
|
|
break;
|
|
}
|
|
var process = await Process.start(executable, arguments);
|
|
var timedOut = false;
|
|
var timer = new Timer(timeout, () {
|
|
timedOut = true;
|
|
Process.killPid(process.pid);
|
|
});
|
|
var exitCode = await process.exitCode;
|
|
timer.cancel();
|
|
if (timedOut) {
|
|
print("Timeout: $cmdline");
|
|
break;
|
|
} else if (exitCode == 0) {
|
|
print("Success: $cmdline");
|
|
process.stdout.drain();
|
|
process.stderr.drain();
|
|
} else {
|
|
var stdout = await utf8.decodeStream(process.stdout);
|
|
var stderr = await utf8.decodeStream(process.stderr);
|
|
print("");
|
|
print("=== FAILURE ===");
|
|
for (int i = 0; i <= commandIndex; i++) {
|
|
print("command: ${commands[i].join(' ')}");
|
|
}
|
|
print("exitCode: $exitCode");
|
|
print("stdout:");
|
|
print(stdout);
|
|
print("stderr:");
|
|
print(stderr);
|
|
io.exitCode = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
taskEnd();
|
|
}
|
|
|
|
Future<void> shard(
|
|
List<String> Function(String) createDartCommand,
|
|
int shardIndex,
|
|
String extension,
|
|
) async {
|
|
while (!remainingTimeout.isNegative) {
|
|
await test(createDartCommand, shardIndex, extension);
|
|
}
|
|
}
|
|
|
|
Future<void> flagFuzz(
|
|
List<String> Function(String) createDartCommand,
|
|
String extension,
|
|
) async {
|
|
stopwatch.start();
|
|
|
|
await Directory("out/dartfuzz").create();
|
|
|
|
var executable = "out/ReleaseX64/dartvm";
|
|
var arguments = [
|
|
...alwaysFlags,
|
|
...createDartCommand("out/dartfuzz/expected.$extension"),
|
|
];
|
|
var processResult = await Process.run(executable, arguments);
|
|
if (processResult.exitCode != 0) {
|
|
print("=== FAILURE ===");
|
|
print("command: $executable ${arguments.join(' ')}");
|
|
print("stdout:");
|
|
print(processResult.stdout);
|
|
print("stderr:");
|
|
print(processResult.stderr);
|
|
io.exitCode = 1;
|
|
return;
|
|
}
|
|
|
|
for (var i = 0; i < Platform.numberOfProcessors; i++) {
|
|
shard(createDartCommand, i, extension);
|
|
}
|
|
}
|