[wasm] Remove foreground compilation logic

This unifies the logic used for foreground compilation and background
compilation. The main thread used a separate
{FetchAndExecuteCompilationUnit} function so far, which implements the
same as the {BackgroundCompileTask}, but without compiling in batches.

This CL removes that method, and uses the same
{ExecuteCompilationUnits} method from both foreground and background
tasks.

R=mstarzinger@chromium.org

Bug: v8:8916
Change-Id: Id30edb766c46d860a5b0ef45386af7e9fd6a1cc3
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1564191
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#60790}
This commit is contained in:
Clemens Hammacher 2019-04-11 11:38:12 +02:00 committed by Commit Bot
parent bb0454ac45
commit 8d30bd8231

View File

@ -313,7 +313,8 @@ class CompilationStateImpl {
void OnFinishedUnits(Vector<WasmCode*>);
void OnBackgroundTaskStopped(int task_id, const WasmFeatures& detected);
void PublishDetectedFeatures(Isolate* isolate, const WasmFeatures& detected);
void UpdateDetectedFeatures(const WasmFeatures& detected);
void PublishDetectedFeatures(Isolate*);
void RestartBackgroundTasks();
void SetError();
@ -343,6 +344,11 @@ class CompilationStateImpl {
return wire_bytes_storage_;
}
const std::shared_ptr<BackgroundCompileToken>& background_compile_token()
const {
return background_compile_token_;
}
private:
NativeModule* const native_module_;
const std::shared_ptr<BackgroundCompileToken> background_compile_token_;
@ -671,36 +677,115 @@ void RecordStats(const Code code, Counters* counters) {
counters->wasm_reloc_size()->Increment(code->relocation_info()->length());
}
// Run by the main thread to take part in compilation. Only used for synchronous
// compilation.
bool FetchAndExecuteCompilationUnit(WasmEngine* wasm_engine,
CompilationEnv* env,
NativeModule* native_module,
CompilationStateImpl* compilation_state,
WasmFeatures* detected,
Counters* counters) {
DisallowHeapAccess no_heap_access;
constexpr int kMainThreadTaskId = -1;
// Run by the main thread and background tasks to take part in compilation.
void ExecuteCompilationUnits(
const std::shared_ptr<BackgroundCompileToken>& token, Counters* counters,
int task_id) {
TRACE_COMPILE("Compiling (task %d)...\n", task_id);
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"), "ExecuteCompilationUnits");
const bool is_foreground = task_id == kMainThreadTaskId;
// The main thread uses task id 0, which might collide with one of the
// background tasks. This is fine, as it will only cause some contention on
// the one queue, but work otherwise.
constexpr int kMainThreadTaskId = 0;
std::unique_ptr<WasmCompilationUnit> unit =
compilation_state->GetNextCompilationUnit(kMainThreadTaskId);
if (unit == nullptr) return false;
if (is_foreground) task_id = 0;
WasmCompilationResult result = unit->ExecuteCompilation(
wasm_engine, env, compilation_state->GetWireBytesStorage(), counters,
detected);
Platform* platform = V8::GetCurrentPlatform();
// Deadline is in 50ms from now.
static constexpr double kBackgroundCompileTimeLimit =
50.0 / base::Time::kMillisecondsPerSecond;
const double deadline =
platform->MonotonicallyIncreasingTime() + kBackgroundCompileTimeLimit;
if (result.succeeded()) {
WasmCodeRefScope code_ref_scope;
WasmCode* code = native_module->AddCompiledCode(std::move(result));
compilation_state->OnFinishedUnit(code);
// These fields are initialized in a {BackgroundCompileScope} before
// starting compilation.
base::Optional<CompilationEnv> env;
std::shared_ptr<WireBytesStorage> wire_bytes;
std::shared_ptr<const WasmModule> module;
WasmEngine* wasm_engine = nullptr;
std::unique_ptr<WasmCompilationUnit> unit;
WasmFeatures detected_features = kNoWasmFeatures;
auto stop = [is_foreground, task_id,
&detected_features](BackgroundCompileScope& compile_scope) {
if (is_foreground) {
compile_scope.compilation_state()->UpdateDetectedFeatures(
detected_features);
} else {
compilation_state->SetError();
compile_scope.compilation_state()->OnBackgroundTaskStopped(
task_id, detected_features);
}
return true;
};
// Preparation (synchronized): Initialize the fields above and get the first
// compilation unit.
{
BackgroundCompileScope compile_scope(token);
if (compile_scope.cancelled()) return;
env.emplace(compile_scope.native_module()->CreateCompilationEnv());
wire_bytes = compile_scope.compilation_state()->GetWireBytesStorage();
module = compile_scope.native_module()->shared_module();
wasm_engine = compile_scope.native_module()->engine();
unit = compile_scope.compilation_state()->GetNextCompilationUnit(task_id);
if (unit == nullptr) return stop(compile_scope);
}
std::vector<WasmCompilationResult> results_to_publish;
auto publish_results = [&results_to_publish](
BackgroundCompileScope* compile_scope) {
if (results_to_publish.empty()) return;
WasmCodeRefScope code_ref_scope;
std::vector<WasmCode*> code_vector =
compile_scope->native_module()->AddCompiledCode(
VectorOf(results_to_publish));
compile_scope->compilation_state()->OnFinishedUnits(VectorOf(code_vector));
results_to_publish.clear();
};
bool compilation_failed = false;
while (true) {
// (asynchronous): Execute the compilation.
WasmCompilationResult result = unit->ExecuteCompilation(
wasm_engine, &env.value(), wire_bytes, counters, &detected_features);
results_to_publish.emplace_back(std::move(result));
// (synchronized): Publish the compilation result and get the next unit.
{
BackgroundCompileScope compile_scope(token);
if (compile_scope.cancelled()) return;
if (!results_to_publish.back().succeeded()) {
// Compile error.
compile_scope.compilation_state()->SetError();
stop(compile_scope);
compilation_failed = true;
break;
}
// Publish TurboFan units immediately to reduce peak memory consumption.
if (result.requested_tier == ExecutionTier::kTurbofan) {
publish_results(&compile_scope);
}
// Get next unit.
if (deadline < platform->MonotonicallyIncreasingTime()) {
unit = nullptr;
} else {
unit =
compile_scope.compilation_state()->GetNextCompilationUnit(task_id);
}
if (unit == nullptr) {
publish_results(&compile_scope);
return stop(compile_scope);
}
}
}
// We only get here if compilation failed. Other exits return directly.
DCHECK(compilation_failed);
USE(compilation_failed);
token->Cancel();
}
void ValidateSequentially(Counters* counters, AccountingAllocator* allocator,
@ -836,8 +921,6 @@ void CompileNativeModule(Isolate* isolate, ErrorThrower* thrower,
compilation_state->SetError();
}
WasmFeatures detected_features;
CompilationEnv env = native_module->CreateCompilationEnv();
// TODO(wasm): This might already execute TurboFan units on the main thread,
// while waiting for baseline compilation to finish. This can introduce
// additional delay.
@ -849,13 +932,11 @@ void CompileNativeModule(Isolate* isolate, ErrorThrower* thrower,
// deterministic compilation; in that case, the single background task will
// execute all compilation.
if (NeedsDeterministicCompile()) continue;
FetchAndExecuteCompilationUnit(isolate->wasm_engine(), &env, native_module,
compilation_state, &detected_features,
isolate->counters());
ExecuteCompilationUnits(compilation_state->background_compile_token(),
isolate->counters(), kMainThreadTaskId);
}
// Publish features from the foreground and background tasks.
compilation_state->PublishDetectedFeatures(isolate, detected_features);
compilation_state->PublishDetectedFeatures(isolate);
if (compilation_state->failed()) {
ValidateSequentially(isolate->counters(), isolate->allocator(),
@ -877,103 +958,7 @@ class BackgroundCompileTask : public CancelableTask {
task_id_(task_id) {}
void RunInternal() override {
TRACE_COMPILE("(3b) Compiling...\n");
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"),
"BackgroundCompileTask::RunInternal");
Platform* platform = V8::GetCurrentPlatform();
// Deadline is in 50ms from now.
static constexpr double kBackgroundCompileTimeLimit =
50.0 / base::Time::kMillisecondsPerSecond;
const double deadline =
platform->MonotonicallyIncreasingTime() + kBackgroundCompileTimeLimit;
// These fields are initialized in a {BackgroundCompileScope} before
// starting compilation.
base::Optional<CompilationEnv> env;
std::shared_ptr<WireBytesStorage> wire_bytes;
std::shared_ptr<const WasmModule> module;
WasmEngine* wasm_engine = nullptr;
std::unique_ptr<WasmCompilationUnit> unit;
WasmFeatures detected_features = kNoWasmFeatures;
// Preparation (synchronized): Initialize the fields above and get the first
// compilation unit.
{
BackgroundCompileScope compile_scope(token_);
if (compile_scope.cancelled()) return;
env.emplace(compile_scope.native_module()->CreateCompilationEnv());
wire_bytes = compile_scope.compilation_state()->GetWireBytesStorage();
module = compile_scope.native_module()->shared_module();
wasm_engine = compile_scope.native_module()->engine();
unit =
compile_scope.compilation_state()->GetNextCompilationUnit(task_id_);
if (unit == nullptr) {
compile_scope.compilation_state()->OnBackgroundTaskStopped(
task_id_, detected_features);
return;
}
}
std::vector<WasmCompilationResult> results_to_publish;
auto publish_results =
[&results_to_publish](BackgroundCompileScope* compile_scope) {
if (results_to_publish.empty()) return;
WasmCodeRefScope code_ref_scope;
std::vector<WasmCode*> code_vector =
compile_scope->native_module()->AddCompiledCode(
VectorOf(results_to_publish));
compile_scope->compilation_state()->OnFinishedUnits(
VectorOf(code_vector));
results_to_publish.clear();
};
bool compilation_failed = false;
while (true) {
// (asynchronous): Execute the compilation.
WasmCompilationResult result =
unit->ExecuteCompilation(wasm_engine, &env.value(), wire_bytes,
async_counters_.get(), &detected_features);
results_to_publish.emplace_back(std::move(result));
// (synchronized): Publish the compilation result and get the next unit.
{
BackgroundCompileScope compile_scope(token_);
if (compile_scope.cancelled()) return;
if (!results_to_publish.back().succeeded()) {
// Compile error.
compile_scope.compilation_state()->SetError();
compile_scope.compilation_state()->OnBackgroundTaskStopped(
task_id_, detected_features);
compilation_failed = true;
break;
}
// Publish TurboFan units immediately to reduce peak memory consumption.
if (result.requested_tier == ExecutionTier::kTurbofan) {
publish_results(&compile_scope);
}
// Get next unit.
if (deadline < platform->MonotonicallyIncreasingTime()) {
unit = nullptr;
} else {
unit = compile_scope.compilation_state()->GetNextCompilationUnit(
task_id_);
}
if (unit == nullptr) {
publish_results(&compile_scope);
compile_scope.compilation_state()->OnBackgroundTaskStopped(
task_id_, detected_features);
return;
}
}
}
// We only get here if compilation failed. Other exits return directly.
DCHECK(compilation_failed);
USE(compilation_failed);
token_->Cancel();
ExecuteCompilationUnits(token_, async_counters_.get(), task_id_);
}
private:
@ -1195,8 +1180,7 @@ void AsyncCompileJob::FinishCompile() {
// We can only update the feature counts once the entire compile is done.
auto compilation_state =
Impl(module_object_->native_module()->compilation_state());
compilation_state->PublishDetectedFeatures(
isolate_, *compilation_state->detected_features());
compilation_state->PublishDetectedFeatures(isolate_);
// TODO(bbudge) Allow deserialization without wrapper compilation, so we can
// just compile wrappers here.
@ -1967,13 +1951,17 @@ void CompilationStateImpl::OnBackgroundTaskStopped(
RestartBackgroundTasks();
}
void CompilationStateImpl::PublishDetectedFeatures(
Isolate* isolate, const WasmFeatures& detected) {
void CompilationStateImpl::UpdateDetectedFeatures(
const WasmFeatures& detected) {
base::MutexGuard guard(&mutex_);
UnionFeaturesInto(&detected_features_, detected);
}
void CompilationStateImpl::PublishDetectedFeatures(Isolate* isolate) {
// Notifying the isolate of the feature counts must take place under
// the mutex, because even if we have finished baseline compilation,
// tiering compilations may still occur in the background.
base::MutexGuard guard(&mutex_);
UnionFeaturesInto(&detected_features_, detected);
UpdateFeatureUseCounts(isolate, detected_features_);
}