blob: 1348e7a1426974bcbcf9f5b32395a71851ba46c5 [file] [log] [blame]
// 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 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: 45);
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;
taskStart() {
if (pendingTaskCount++ == 0) {
pendingTimer = new Timer.periodic(statusTimeout, (timer) {
print(
"$pendingTaskCount tasks still running after "
"${stopwatch.elapsed.inMinutes} minutes",
);
});
}
}
taskEnd() {
if (--pendingTaskCount == 0) {
pendingTimer.cancel();
}
}
test(List<String> Function(String) createDartCommand, int taskIndex) async {
taskStart();
var dartCommand = createDartCommand("out/dartfuzz/$taskIndex.js");
var dartScript = dartCommand[0];
var dartArguments = dartCommand.getRange(1, dartCommand.length).toList();
var buildDir = oneOf(buildDirs);
var commands;
if (random.nextBool()) {
// JIT
commands = [
[
"$buildDir/dart",
...someJitRuntimeFlags(),
dartScript,
...dartArguments,
],
["diff", "out/dartfuzz/expected.js", "out/dartfuzz/$taskIndex.js"],
];
} else {
// AOT
commands = [
[
"out/ReleaseX64/dart",
"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",
...someAotRuntimeFlags(),
"out/dartfuzz/$taskIndex.elf",
...dartArguments,
],
["diff", "out/dartfuzz/expected.js", "out/dartfuzz/$taskIndex.js"],
];
}
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();
}
shard(List<String> Function(String) createDartCommand, int shardIndex) async {
while (!remainingTimeout.isNegative) {
await test(createDartCommand, shardIndex);
}
}
flagFuzz(List<String> Function(String) createDartCommand) async {
stopwatch.start();
await Directory("out/dartfuzz").create();
var executable = "out/ReleaseX64/dart";
var arguments = createDartCommand("out/dartfuzz/expected.js");
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);
}
}