Commit d6a02c02 authored by Andreas Haas's avatar Andreas Haas Committed by Commit Bot

[predictable] Run worker task on the foreground task runner

On the PredictablePlatform, worker tasks were executed immediately
instead of posting them in a task queue first. This approach caused
problems because the execution of the worker task blocked progress of
the posting task, and the worker task was always executed in the
context of the posting task, e.g. with an already open HandleScope.

With this CL, worker tasks get posted into the foreground task queue
of the nullptr isolate instead of executing them immediately.
The tasks of the nullptr isolate are then executed after a task of
some other task queue is executed. As the worker tasks are thereby
executed on the same thread as foreground tasks, the behavior is
deterministic.

A consequence of this approach is that each pumping the message loop
of an Isolate may also execute other Isolate's background tasks.

This approach is needed because we don't have a BackgroundTaskRunner but
merely a CallOnWorkerThread method that doesn't know which Isolate the
task corresponds to.

R=clemensb@chromium.org, mlippautz@chromium.org

Bug: v8:9670
Change-Id: I6847ae042146431bc2376d27280be8829f529b95
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2182453
Commit-Queue: Andreas Haas <ahaas@chromium.org>
Reviewed-by: 's avatarClemens Backes <clemensb@chromium.org>
Reviewed-by: 's avatarMichael Lippautz <mlippautz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#67616}
parent 8aa7a464
......@@ -43,9 +43,17 @@ class PredictablePlatform : public Platform {
int NumberOfWorkerThreads() override { return 0; }
void CallOnWorkerThread(std::unique_ptr<Task> task) override {
// It's not defined when background tasks are being executed, so we can just
// execute them right away.
task->Run();
// We post worker tasks on the foreground task runner of the
// {kProcessGlobalPredictablePlatformWorkerTaskQueue} isolate. The task
// queue of the {kProcessGlobalPredictablePlatformWorkerTaskQueue} isolate
// is then executed on the main thread to achieve predictable behavior.
//
// In this context here it is okay to call {GetForegroundTaskRunner} from a
// background thread. The reason is that code is executed sequentially with
// the PredictablePlatform, and that the {DefaultPlatform} does not access
// the isolate but only uses it as the key in a HashMap.
GetForegroundTaskRunner(kProcessGlobalPredictablePlatformWorkerTaskQueue)
->PostTask(std::move(task));
}
void CallDelayedOnWorkerThread(std::unique_ptr<Task> task,
......
......@@ -10,6 +10,7 @@
namespace v8 {
class Isolate;
class Platform;
// Returns a predictable v8::Platform implementation.
......@@ -24,6 +25,13 @@ std::unique_ptr<Platform> MakePredictablePlatform(
std::unique_ptr<Platform> MakeDelayedTasksPlatform(
std::unique_ptr<Platform> platform, int64_t random_seed);
// We use the task queue of {kProcessGlobalPredictablePlatformWorkerTaskQueue}
// for worker tasks of the {PredictablePlatform}. At the moment, {nullptr} is a
// valid value for the isolate. If this ever changes, we either have to allocate
// a core isolate, or refactor the implementation of worker tasks in the
// {PredictablePlatform}.
constexpr Isolate* kProcessGlobalPredictablePlatformWorkerTaskQueue = nullptr;
} // namespace v8
#endif // V8_D8_D8_PLATFORMS_H_
......@@ -3125,6 +3125,17 @@ bool ProcessMessages(
while (v8::platform::PumpMessageLoop(g_default_platform, isolate,
behavior())) {
MicrotasksScope::PerformCheckpoint(isolate);
if (i::FLAG_verify_predictable) {
// In predictable mode we push all background tasks into the foreground
// task queue of the {kProcessGlobalPredictablePlatformWorkerTaskQueue}
// isolate. We execute the tasks after one foreground task has been
// executed.
while (v8::platform::PumpMessageLoop(
g_default_platform,
kProcessGlobalPredictablePlatformWorkerTaskQueue, behavior())) {
}
}
}
if (g_default_platform->IdleTasksEnabled(isolate)) {
v8::platform::RunIdleTasks(g_default_platform, isolate,
......
......@@ -695,6 +695,7 @@ DEFINE_BOOL(wasm_tier_up, true,
"enable tier up to the optimizing compiler (requires --liftoff to "
"have an effect)")
DEFINE_DEBUG_BOOL(trace_wasm_decoder, false, "trace decoding of wasm code")
DEFINE_IMPLICATION(trace_wasm_decoder, single_threaded)
DEFINE_DEBUG_BOOL(trace_wasm_compiler, false, "trace compiling of wasm code")
DEFINE_DEBUG_BOOL(trace_wasm_interpreter, false,
"trace interpretation of wasm code")
......@@ -772,6 +773,7 @@ DEFINE_BOOL(wasm_fuzzer_gen_test, false,
"generate a test case when running a wasm fuzzer")
DEFINE_IMPLICATION(wasm_fuzzer_gen_test, single_threaded)
DEFINE_BOOL(print_wasm_code, false, "Print WebAssembly code")
DEFINE_IMPLICATION(print_wasm_code, single_threaded)
DEFINE_BOOL(print_wasm_stub_code, false, "Print WebAssembly stub code")
DEFINE_BOOL(asm_wasm_lazy_compilation, false,
"enable lazy compilation for asm-wasm modules")
......
......@@ -1035,9 +1035,7 @@ bool ExecuteJSToWasmWrapperCompilationUnits(
return true;
}
bool NeedsDeterministicCompile() {
return FLAG_trace_wasm_decoder || FLAG_wasm_num_compilation_tasks <= 1;
}
bool NeedsDeterministicCompile() { return FLAG_single_threaded; }
// Run by the main thread and background tasks to take part in compilation.
// Returns whether any units were executed.
......@@ -1368,15 +1366,11 @@ void CompileNativeModule(Isolate* isolate, ErrorThrower* thrower,
// are part of initial compilation). Otherwise, just execute baseline units.
bool is_tiering = compilation_state->compile_mode() == CompileMode::kTiering;
auto baseline_only = is_tiering ? kBaselineOnly : kBaselineOrTopTier;
// The main threads contributes to the compilation, except if we need
// deterministic compilation; in that case, the single background task will
// execute all compilation.
if (!NeedsDeterministicCompile()) {
while (ExecuteCompilationUnits(
compilation_state->background_compile_token(), isolate->counters(),
kMainThreadTaskId, baseline_only)) {
// Continue executing compilation units.
}
// The main threads contributes to the compilation.
while (ExecuteCompilationUnits(compilation_state->background_compile_token(),
isolate->counters(), kMainThreadTaskId,
baseline_only)) {
// Continue executing compilation units.
}
// Now wait until baseline compilation finished.
......@@ -1486,15 +1480,11 @@ void RecompileNativeModule(Isolate* isolate, NativeModule* native_module,
// We only wait for tier down. Tier up can happen in the background.
if (tiering_state == kTieredDown) {
// The main thread contributes to the compilation, except if we need
// deterministic compilation; in that case, the single background task will
// execute all compilation.
if (!NeedsDeterministicCompile()) {
while (ExecuteCompilationUnits(
compilation_state->background_compile_token(), isolate->counters(),
kMainThreadTaskId, kBaselineOnly)) {
// Continue executing compilation units.
}
// The main thread contributes to the compilation.
while (ExecuteCompilationUnits(
compilation_state->background_compile_token(), isolate->counters(),
kMainThreadTaskId, kBaselineOnly)) {
// Continue executing compilation units.
}
// Now wait until baseline recompilation finished.
......
......@@ -956,17 +956,10 @@
'regress/regress-356053': [SKIP],
'regress/regress-embedded-cons-string': [SKIP],
# Relies on async compilation which requires background tasks.
'wasm/streaming-error-position': [SKIP],
# Intentionally non-deterministic using shared arraybuffers.
'wasm/atomics-stress': [SKIP],
'wasm/atomics64-stress': [SKIP],
'wasm/futex': [SKIP],
# Deadlocks on predictable platform (https://crbug.com/v8/9760).
'wasm/async-compile': [SKIP],
'wasm/streaming-compile': [SKIP],
}], # 'predictable == True'
##############################################################################
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment