Commit 18c380c3 authored by ahaas's avatar ahaas Committed by Commit bot

[wasm] Split the wasm compilation into two phases for parallel compilation.

Graph construction, graph scheduling, instruction selection, and register
allocation has been moved to ExecuteCompilation, which will eventually be
executed on the background threads. Code generation remains in
FinishCompilation because it has to be executed by the main thread.

Additionally, WasmCompilationUnits are finished more eagerly in
wasm-module.cc to save memory.

R=titzer@chromium.org

Review-Url: https://codereview.chromium.org/1942773002
Cr-Commit-Position: refs/heads/master@{#35973}
parent c89e6eb5
......@@ -2956,85 +2956,105 @@ std::pair<JSGraph*, SourcePositionTable*> BuildGraphForWasmFunction(
return std::make_pair(jsgraph, source_position_table);
}
// Helper function to compile a single function.
Handle<Code> CompileWasmFunction(wasm::ErrorThrower* thrower, Isolate* isolate,
class WasmCompilationUnit {
public:
WasmCompilationUnit(wasm::ErrorThrower* thrower, Isolate* isolate,
wasm::ModuleEnv* module_env,
const wasm::WasmFunction* function) {
const wasm::WasmFunction* function, uint32_t index)
: thrower_(thrower),
isolate_(isolate),
module_env_(module_env),
function_(function),
compilation_zone_(isolate->allocator()),
info_(function->name_length != 0
? module_env->module->GetNameOrNull(function->name_offset,
function->name_length)
: ArrayVector("wasm"),
isolate, &compilation_zone_,
Code::ComputeFlags(Code::WASM_FUNCTION)),
job_(),
index_(index),
ok_(true) {}
void ExecuteCompilation() {
HistogramTimerScope wasm_compile_function_time_scope(
isolate->counters()->wasm_compile_function_time());
isolate_->counters()->wasm_compile_function_time());
if (FLAG_trace_wasm_compiler) {
OFStream os(stdout);
os << "Compiling WASM function "
<< wasm::WasmFunctionName(function, module_env) << std::endl;
<< wasm::WasmFunctionName(function_, module_env_) << std::endl;
os << std::endl;
}
compiler::ZonePool zone_pool(isolate->allocator());
compiler::ZonePool::Scope graph_zone_scope(&zone_pool);
double decode_ms = 0;
size_t node_count = 0;
Zone zone(isolate_->allocator());
std::pair<JSGraph*, SourcePositionTable*> graph_result =
BuildGraphForWasmFunction(graph_zone_scope.zone(), thrower, isolate,
module_env, function, &decode_ms);
BuildGraphForWasmFunction(&zone, thrower_, isolate_, module_env_,
function_, &decode_ms);
JSGraph* jsgraph = graph_result.first;
SourcePositionTable* source_positions = graph_result.second;
if (jsgraph == nullptr) {
return Handle<Code>::null();
ok_ = false;
return;
}
base::ElapsedTimer compile_timer;
base::ElapsedTimer pipeline_timer;
if (FLAG_trace_wasm_decode_time) {
compile_timer.Start();
node_count = jsgraph->graph()->NodeCount();
pipeline_timer.Start();
}
// Run the compiler pipeline to generate machine code.
CallDescriptor* descriptor = wasm::ModuleEnv::GetWasmCallDescriptor(
jsgraph->graph()->zone(), function->sig);
&compilation_zone_, function_->sig);
if (jsgraph->machine()->Is32()) {
descriptor = module_env->GetI32WasmCallDescriptor(jsgraph->graph()->zone(),
descriptor);
}
Code::Flags flags = Code::ComputeFlags(Code::WASM_FUNCTION);
// add flags here if a meaningful name is helpful for debugging.
bool debugging =
#if DEBUG
true;
#else
FLAG_print_opt_code || FLAG_trace_turbo || FLAG_trace_turbo_graph;
#endif
Vector<const char> func_name = module_env->module->GetNameOrNull(
function->name_offset, function->name_length);
Vector<char> buffer;
if (func_name.is_empty()) {
if (debugging) {
buffer = Vector<char>::New(128);
int chars = SNPrintF(buffer, "WASM_function_#%d", function->func_index);
func_name = Vector<const char>::cast(buffer.SubVector(0, chars));
} else {
func_name = ArrayVector("wasm");
descriptor =
module_env_->GetI32WasmCallDescriptor(&compilation_zone_, descriptor);
}
job_.Reset(Pipeline::NewWasmCompilationJob(&info_, jsgraph->graph(),
descriptor, source_positions));
ok_ = job_->OptimizeGraph() == CompilationJob::SUCCEEDED;
// TODO(bradnelson): Improve histogram handling of size_t.
isolate_->counters()->wasm_compile_function_peak_memory_bytes()->AddSample(
static_cast<int>(jsgraph->graph()->zone()->allocation_size()));
if (FLAG_trace_wasm_decode_time) {
double pipeline_ms = pipeline_timer.Elapsed().InMillisecondsF();
PrintF(
"wasm-compilation phase 1 ok: %d bytes, %0.3f ms decode, %zu nodes, "
"%0.3f ms pipeline\n",
static_cast<int>(function_->code_end_offset -
function_->code_start_offset),
decode_ms, node_count, pipeline_ms);
}
CompilationInfo info(func_name, isolate, jsgraph->graph()->zone(), flags);
base::SmartPointer<CompilationJob> job(Pipeline::NewWasmCompilationJob(
&info, jsgraph->graph(), descriptor, source_positions));
Handle<Code> code = Handle<Code>::null();
if (job->OptimizeGraph() == CompilationJob::SUCCEEDED &&
job->GenerateCode() == CompilationJob::SUCCEEDED) {
code = info.code();
}
buffer.Dispose();
if (!code.is_null()) {
Handle<Code> FinishCompilation() {
if (!ok_) {
return Handle<Code>::null();
}
if (job_->GenerateCode() != CompilationJob::SUCCEEDED) {
return Handle<Code>::null();
}
base::ElapsedTimer compile_timer;
if (FLAG_trace_wasm_decode_time) {
compile_timer.Start();
}
Handle<Code> code = info_.code();
DCHECK(!code.is_null());
DCHECK(code->deoptimization_data() == nullptr ||
code->deoptimization_data()->length() == 0);
Handle<FixedArray> deopt_data =
isolate->factory()->NewFixedArray(2, TENURED);
if (!module_env->instance->js_object.is_null()) {
deopt_data->set(0, *module_env->instance->js_object);
deopt_data->set(1, Smi::FromInt(function->func_index));
} else if (func_name.start() != nullptr) {
MaybeHandle<String> maybe_name =
isolate->factory()->NewStringFromUtf8(func_name);
isolate_->factory()->NewFixedArray(2, TENURED);
if (!module_env_->instance->js_object.is_null()) {
deopt_data->set(0, *module_env_->instance->js_object);
deopt_data->set(1, Smi::FromInt(function_->func_index));
} else if (info_.GetDebugName().get() != nullptr) {
MaybeHandle<String> maybe_name = isolate_->factory()->NewStringFromUtf8(
CStrVector(info_.GetDebugName().get()));
if (!maybe_name.is_null())
deopt_data->set(0, *maybe_name.ToHandleChecked());
}
......@@ -3042,71 +3062,62 @@ Handle<Code> CompileWasmFunction(wasm::ErrorThrower* thrower, Isolate* isolate,
code->set_deoptimization_data(*deopt_data);
RecordFunctionCompilation(
Logger::FUNCTION_TAG, &info, "WASM_function", function->func_index,
module_env->module->GetName(function->name_offset,
function->name_length));
}
Logger::FUNCTION_TAG, &info_, "WASM_function", function_->func_index,
module_env_->module->GetName(function_->name_offset,
function_->name_length));
if (FLAG_trace_wasm_decode_time) {
double compile_ms = compile_timer.Elapsed().InMillisecondsF();
PrintF(
"wasm-compile ok: %d bytes, %0.3f ms decode, %d nodes, %0.3f ms "
"compile\n",
static_cast<int>(function->code_end_offset -
function->code_start_offset),
decode_ms, static_cast<int>(jsgraph->graph()->NodeCount()), compile_ms);
}
// TODO(bradnelson): Improve histogram handling of size_t.
isolate->counters()->wasm_compile_function_peak_memory_bytes()->AddSample(
static_cast<int>(jsgraph->graph()->zone()->allocation_size()));
graph_zone_scope.Destroy();
return code;
}
class WasmCompilationUnit {
public:
WasmCompilationUnit(wasm::ErrorThrower* thrower, Isolate* isolate,
wasm::ModuleEnv* module_env,
const wasm::WasmFunction* function)
: thrower_(thrower),
isolate_(isolate),
module_env_(module_env),
function_(function) {}
void ExecuteCompilation() {
if (function_->external) {
return;
}
// TODO(ahaas): The parallelizable parts of the compilation should move from
// FinishCompilation to here.
PrintF("wasm-code-generation ok: %d bytes, %0.3f ms code generation\n",
static_cast<int>(function_->code_end_offset -
function_->code_start_offset),
compile_ms);
}
Handle<Code> FinishCompilation() {
return CompileWasmFunction(thrower_, isolate_, module_env_, function_);
return code;
}
wasm::ErrorThrower* thrower_;
Isolate* isolate_;
wasm::ModuleEnv* module_env_;
const wasm::WasmFunction* function_;
Zone compilation_zone_;
CompilationInfo info_;
base::SmartPointer<CompilationJob> job_;
uint32_t index_;
bool ok_;
};
WasmCompilationUnit* CreateWasmCompilationUnit(
wasm::ErrorThrower* thrower, Isolate* isolate, wasm::ModuleEnv* module_env,
const wasm::WasmFunction* function) {
return new WasmCompilationUnit(thrower, isolate, module_env, function);
const wasm::WasmFunction* function, uint32_t index) {
return new WasmCompilationUnit(thrower, isolate, module_env, function, index);
}
void ExecuteCompilation(WasmCompilationUnit* unit) {
unit->ExecuteCompilation();
}
uint32_t GetIndexOfWasmCompilationUnit(WasmCompilationUnit* unit) {
return unit->index_;
}
Handle<Code> FinishCompilation(WasmCompilationUnit* unit) {
Handle<Code> result = unit->FinishCompilation();
delete unit;
return result;
}
// Helper function to compile a single function.
Handle<Code> CompileWasmFunction(wasm::ErrorThrower* thrower, Isolate* isolate,
wasm::ModuleEnv* module_env,
const wasm::WasmFunction* function) {
WasmCompilationUnit* unit =
CreateWasmCompilationUnit(thrower, isolate, module_env, function, 0);
ExecuteCompilation(unit);
return FinishCompilation(unit);
}
} // namespace compiler
} // namespace internal
} // namespace v8
......@@ -55,14 +55,14 @@ Handle<JSFunction> CompileJSToWasmWrapper(
WasmCompilationUnit* CreateWasmCompilationUnit(
wasm::ErrorThrower* thrower, Isolate* isolate, wasm::ModuleEnv* module_env,
const wasm::WasmFunction* function);
const wasm::WasmFunction* function, uint32_t index);
void ExecuteCompilation(WasmCompilationUnit* unit);
int GetIndexOfWasmCompilationUnit(WasmCompilationUnit* unit);
Handle<Code> FinishCompilation(WasmCompilationUnit* unit);
uint32_t GetIndexOfWasmCompilationUnit(WasmCompilationUnit* unit);
// Abstracts details of building TurboFan graph nodes for WASM to separate
// the WASM decoder from the internal details of TurboFan.
class WasmTrapHelper;
......
......@@ -509,6 +509,9 @@ MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
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) {
// Create a placeholder code object for all functions.
// TODO(ahaas): Maybe we could skip this for external functions.
......@@ -520,14 +523,26 @@ MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
i++) {
if (!functions[i].external) {
compilation_units[i] = compiler::CreateWasmCompilationUnit(
&thrower, isolate, &module_env, &functions[i]);
&thrower, isolate, &module_env, &functions[i], i);
}
}
for (uint32_t i = FLAG_skip_compiling_wasm_funcs; i < functions.size();
i++) {
if (!functions[i].external) {
compiler::ExecuteCompilation(compilation_units[i]);
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);
}
if (index < functions.size()) {
if (!functions[index].external) {
compiler::ExecuteCompilation(compilation_units[index]);
executed_units.push(compilation_units[index]);
index++;
}
} else {
break;
}
}
}
......@@ -554,7 +569,7 @@ MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
func.sig, str, str_null);
} else {
if (FLAG_wasm_parallel_compilation) {
code = compiler::FinishCompilation(compilation_units[i]);
code = results[i];
} else {
// Compile the function.
code = compiler::CompileWasmFunction(&thrower, isolate, &module_env,
......
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