Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1121)

Unified Diff: src/wasm/wasm-module.cc

Issue 1961973002: [wasm] Implement parallel compilation. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/wasm/wasm-module.cc
diff --git a/src/wasm/wasm-module.cc b/src/wasm/wasm-module.cc
index 28fdb105dc834cd7a0caf8f26657fa4c5970692d..9d870aa5fd04645bb0320957b50bccbb1272470f 100644
--- a/src/wasm/wasm-module.cc
+++ b/src/wasm/wasm-module.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "src/base/atomic-utils.h"
#include "src/macro-assembler.h"
#include "src/objects.h"
#include "src/property-descriptor.h"
@@ -130,11 +131,11 @@ class WasmLinker {
// Create a placeholder code object and encode the corresponding index in
// the {constant_pool_offset} field of the code object.
// TODO(titzer): placeholder code objects are somewhat dangerous.
- Handle<Code> self(nullptr, isolate_);
byte buffer[] = {0, 0, 0, 0, 0, 0, 0, 0}; // fake instructions.
CodeDesc desc = {buffer, 8, 8, 0, 0, nullptr};
Handle<Code> code = isolate_->factory()->NewCode(
- desc, Code::KindField::encode(Code::WASM_FUNCTION), self);
+ desc, Code::KindField::encode(Code::WASM_FUNCTION),
+ Handle<Object>::null());
code->set_constant_pool_offset(index + kPlaceholderMarker);
placeholder_code_[index] = code;
function_code_[index] = code;
@@ -398,6 +399,67 @@ static MaybeHandle<JSFunction> LookupFunction(
return Handle<JSFunction>::cast(function);
}
+// Fetches the compilation unit of a wasm function and executes its parallel
+// phase.
+bool FetchAndExecuteCompilation(
titzer 2016/05/10 12:32:10 Put this into an anonymous namespace.
ahaas 2016/05/11 09:52:21 done.
+ Isolate* isolate,
+ std::vector<compiler::WasmCompilationUnit*>* compilation_units,
+ std::queue<compiler::WasmCompilationUnit*>* executed_units,
+ base::Mutex* result_mutex, base::AtomicNumber<size_t>* next_unit) {
+ DisallowHeapAllocation no_allocation;
+ DisallowHandleAllocation no_handles;
+ DisallowHandleDereference no_deref;
+ DisallowCodeDependencyChange no_dependency_change;
+
+ // - 1 because AtomicIntrement returns the value after the atomic increment.
+ size_t index = next_unit->Increment(1) - 1;
+ if (index >= compilation_units->size()) {
+ return false;
+ }
+
+ compiler::WasmCompilationUnit* unit = compilation_units->at(index);
+ if (unit != nullptr) {
+ compiler::ExecuteCompilation(unit);
+ {
+ base::LockGuard<base::Mutex> guard(result_mutex);
+ executed_units->push(unit);
+ }
+ }
+ return true;
+}
+
+class WasmCompilationTask : public CancelableTask {
+ public:
+ WasmCompilationTask(
+ Isolate* isolate,
+ std::vector<compiler::WasmCompilationUnit*>* compilation_units,
+ std::queue<compiler::WasmCompilationUnit*>* executed_units,
+ base::Semaphore* on_finished, base::Mutex* result_mutex,
+ base::AtomicNumber<size_t>* next_unit)
+ : CancelableTask(isolate),
+ isolate_(isolate),
+ compilation_units_(compilation_units),
+ executed_units_(executed_units),
+ on_finished_(on_finished),
+ result_mutex_(result_mutex),
+ next_unit_(next_unit) {}
+
+ void RunInternal() override {
+ while (FetchAndExecuteCompilation(isolate_, compilation_units_,
+ executed_units_, result_mutex_,
+ next_unit_)) {
+ }
+ on_finished_->Signal();
+ }
+
+ Isolate* isolate_;
+ std::vector<compiler::WasmCompilationUnit*>* compilation_units_;
+ std::queue<compiler::WasmCompilationUnit*>* executed_units_;
+ base::Semaphore* on_finished_;
+ base::Mutex* result_mutex_;
+ base::AtomicNumber<size_t>* next_unit_;
+};
+
// Instantiates a wasm module as a JSObject.
// * allocates a backing store of {mem_size} bytes.
// * installs a named property "memory" for that buffer if exported
@@ -507,46 +569,119 @@ MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
isolate->counters()->wasm_functions_per_module()->AddSample(
static_cast<int>(functions.size()));
+ //-----------------------------------------------------------------------
+ // For parallel compilation:
+ // 1) The main thread allocates a compilation unit for each wasm function
+ // and stores them in the vector compilation_units.
titzer 2016/05/10 12:32:10 We've adopted the {} style for comments, so s/comp
ahaas 2016/05/11 09:52:21 done.
+ // 2) The main thread spawns WasmCompilationTasks which run on the
+ // background threads.
+ // 3.a) The background threads and the main thread pick one compilation unit
+ // at a time and execute the parallel phase of the compilation unit.
+ // After finishing the execution of the parallel phase, the result is
+ // enqueued in executed_units.
+ // 3.b) If executed_units contains a compilation unit, the main thread
+ // dequeues it and finishes the compilation.
+ // 4) After the parallel phase of all compilation units has started, the
+ // main thread waits for all WasmCompilationTasks to finish.
+ // 5) The main thread finishes the compilation.
+
std::vector<compiler::WasmCompilationUnit*> compilation_units(
functions.size());
std::queue<compiler::WasmCompilationUnit*> executed_units;
std::vector<Handle<Code>> results(functions.size());
- if (FLAG_wasm_parallel_compilation) {
+ if (FLAG_wasm_num_compilation_tasks != 0) {
titzer 2016/05/10 12:32:10 This function is getting huge. Can you split out t
ahaas 2016/05/11 09:52:21 Done.
+ CanonicalHandleScope canonical(isolate);
titzer 2016/05/10 12:32:10 Comment on why we need a canonical handle scope he
ahaas 2016/05/11 09:52:21 Done.
+
// Create a placeholder code object for all functions.
// TODO(ahaas): Maybe we could skip this for external functions.
for (uint32_t i = 0; i < functions.size(); i++) {
linker.GetFunctionCode(i);
}
+ // 1) The main thread allocates a compilation unit for each wasm function
+ // and stores them in the vector compilation_units.
for (uint32_t i = FLAG_skip_compiling_wasm_funcs; i < functions.size();
i++) {
if (!functions[i].external) {
compilation_units[i] = compiler::CreateWasmCompilationUnit(
&thrower, isolate, &module_env, &functions[i], i);
+ } else {
+ compilation_units[i] = nullptr;
}
}
+ // 2) The main thread spawns WasmCompilationTasks which run on the
+ // background threads.
+ const size_t max_num_tasks =
+ Min(static_cast<size_t>(FLAG_wasm_num_compilation_tasks),
+ V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads());
+
+ base::SmartArrayPointer<uint32_t> task_ids(new uint32_t[max_num_tasks]);
+
+ base::SmartPointer<base::Semaphore> pending_tasks(new base::Semaphore(0));
+ base::Mutex result_mutex;
+ base::AtomicNumber<size_t> next_unit(
+ static_cast<size_t>(FLAG_skip_compiling_wasm_funcs));
+
+ for (size_t i = 0; i < max_num_tasks; i++) {
+ WasmCompilationTask* task = new WasmCompilationTask(
+ isolate, &compilation_units, &executed_units, pending_tasks.get(),
+ &result_mutex, &next_unit);
+ task_ids[i] = task->id();
+ V8::GetCurrentPlatform()->CallOnBackgroundThread(
+ task, v8::Platform::kShortRunningTask);
+ }
+
index = FLAG_skip_compiling_wasm_funcs;
- while (true) {
- while (!executed_units.empty()) {
- compiler::WasmCompilationUnit* unit = executed_units.front();
- executed_units.pop();
- int i = compiler::GetIndexOfWasmCompilationUnit(unit);
- results[i] = compiler::FinishCompilation(unit);
+ bool done = false;
+ while (!done) {
+ // The steps loop contains the steps 3.a, 4, and 3.b, are intertwined in
+ // this loop for the following reasons:
+ // * We cannot wait with the sequential fixup (3b) until after the
+ // parallel execution has finished because we would run out of memory.
+ // * The fixup has to done after the waiting because otherwise we would
+ // miss the last functions.
+ // * The main thread should to participate in the parallel execution to
+ // guarantee progress even if the worker threads don't do any work.
+
+ // 3.a) The background threads and the main thread pick one compilation
+ // unit at a time and execute the parallel phase of the compilation
+ // unit. After finishing the execution of the parallel phase, the
+ // result is enqueued in executed_units.
+ if (!FetchAndExecuteCompilation(isolate, &compilation_units,
+ &executed_units, &result_mutex,
+ &next_unit)) {
+ // 4) After the parallel phase of all compilation units has started,
+ // the main thread waits for all WasmCompilationTasks to finish.
+ for (size_t i = 0; i < max_num_tasks; i++) {
+ if (!isolate->cancelable_task_manager()->TryAbort(task_ids[i])) {
+ pending_tasks->Wait();
+ }
+ }
+ done = true;
}
- if (index < functions.size()) {
- if (!functions[index].external) {
- compiler::ExecuteCompilation(compilation_units[index]);
- executed_units.push(compilation_units[index]);
- index++;
+ // 3.b) If executed_units contains a compilation unit, the main thread
+ // dequeues it and finishes the compilation.
+ while (!executed_units.empty()) {
+ compiler::WasmCompilationUnit* unit = nullptr;
+ {
+ base::LockGuard<base::Mutex> guard(&result_mutex);
+ if (!executed_units.empty()) {
+ unit = executed_units.front();
+ executed_units.pop();
+ }
+ }
+ if (unit != nullptr) {
+ int j = compiler::GetIndexOfWasmCompilationUnit(unit);
+ if (!functions[j].external) {
+ results[j] = compiler::FinishCompilation(unit);
+ }
}
- } else {
- break;
}
}
}
-
+ // 5) The main thread finishes the compilation.
// First pass: compile each function and initialize the code table.
titzer 2016/05/10 12:32:10 This comment is now out of date.
ahaas 2016/05/11 09:52:21 Done.
for (uint32_t i = FLAG_skip_compiling_wasm_funcs; i < functions.size();
i++) {
@@ -568,10 +703,11 @@ MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
function.ToHandleChecked(),
func.sig, str, str_null);
} else {
- if (FLAG_wasm_parallel_compilation) {
+ if (FLAG_wasm_num_compilation_tasks != 0) {
code = results[i];
} else {
// Compile the function.
+ CanonicalHandleScope canonical(isolate);
code = compiler::CompileWasmFunction(&thrower, isolate, &module_env,
&func);
}

Powered by Google App Engine
This is Rietveld 408576698