Reland "[wasm] Perform NativeModule tier down in parallel."
This is a reland offaccc95b77
Since1c9bb77de5
, async jobs use existing entry in native module cache and skip recompilation so we need to fix the test. Original change's description: > Reland "[wasm] Perform NativeModule tier down in parallel." > > This is a reland of3352fcc900
> > Disable stress-opt for test and check recompilation before clearing > callbacks. > > Original change's description: > > [wasm] Perform NativeModule tier down in parallel. > > > > Reuse logic in {CompileNativeModule} function in module-compiler.cc: > > initialize parallel compile jobs, then wait for them to finish while > > taking part in this compilation. > > > > Bug: v8:9654 > > Change-Id: I9974d9f8b516e9faec716a592c7c0ee9c7077d8e > > Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1977041 > > Commit-Queue: Z Nguyen-Huu <duongn@microsoft.com> > > Reviewed-by: Clemens Backes <clemensb@chromium.org> > > Cr-Commit-Position: refs/heads/master@{#65763} > > Bug: v8:9654 > Change-Id: I8e8830f05e189596207365b7332a2cc25e493e47 > Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2002945 > Commit-Queue: Z Nguyen-Huu <duongn@microsoft.com> > Reviewed-by: Clemens Backes <clemensb@chromium.org> > Cr-Commit-Position: refs/heads/master@{#65901} Bug: v8:9654 Change-Id: Ia63b86d4275088d93202046bc9823e6202b7991a Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2012986 Reviewed-by: Clemens Backes <clemensb@chromium.org> Commit-Queue: Z Nguyen-Huu <duongn@microsoft.com> Cr-Commit-Position: refs/heads/master@{#65929}
This commit is contained in:
parent
c93be468ff
commit
30f94ea4c9
@ -92,7 +92,8 @@ class WireBytesStorage {
|
||||
enum class CompilationEvent : uint8_t {
|
||||
kFinishedBaselineCompilation,
|
||||
kFinishedTopTierCompilation,
|
||||
kFailedCompilation
|
||||
kFailedCompilation,
|
||||
kFinishedRecompilation
|
||||
};
|
||||
|
||||
// The implementation of {CompilationState} lives in module-compiler.cc.
|
||||
@ -117,6 +118,7 @@ class CompilationState {
|
||||
bool failed() const;
|
||||
V8_EXPORT_PRIVATE bool baseline_compilation_finished() const;
|
||||
V8_EXPORT_PRIVATE bool top_tier_compilation_finished() const;
|
||||
V8_EXPORT_PRIVATE bool recompilation_finished() const;
|
||||
|
||||
// Override {operator delete} to avoid implicit instantiation of {operator
|
||||
// delete} with {size_t} argument. The {size_t} argument would be incorrect.
|
||||
|
@ -381,6 +381,9 @@ class CompilationStateImpl {
|
||||
// is invoked which triggers background compilation.
|
||||
void InitializeCompilationProgress(bool lazy_module, int num_wrappers);
|
||||
|
||||
// Initialize compilation progress for recompilation of the whole module.
|
||||
void InitializeRecompilationProgress(ExecutionTier tier);
|
||||
|
||||
// Add the callback function to be called on compilation events. Needs to be
|
||||
// set before {AddCompilationUnits} is run to ensure that it receives all
|
||||
// events. The callback object must support being deleted from any thread.
|
||||
@ -404,7 +407,8 @@ class CompilationStateImpl {
|
||||
void OnFinishedUnits(Vector<WasmCode*>);
|
||||
void OnFinishedJSToWasmWrapperUnits(int num);
|
||||
void TriggerCallbacks(bool completes_baseline_compilation,
|
||||
bool completes_top_tier_compilation);
|
||||
bool completes_top_tier_compilation,
|
||||
bool completes_recompilation = false);
|
||||
|
||||
void OnBackgroundTaskStopped(int task_id, const WasmFeatures& detected);
|
||||
void UpdateDetectedFeatures(const WasmFeatures& detected);
|
||||
@ -427,6 +431,11 @@ class CompilationStateImpl {
|
||||
return outstanding_top_tier_functions_ == 0;
|
||||
}
|
||||
|
||||
bool recompilation_finished() const {
|
||||
base::MutexGuard guard(&callbacks_mutex_);
|
||||
return outstanding_recompilation_functions_ == 0;
|
||||
}
|
||||
|
||||
CompileMode compile_mode() const { return compile_mode_; }
|
||||
Counters* counters() const { return async_counters_.get(); }
|
||||
WasmFeatures* detected_features() { return &detected_features_; }
|
||||
@ -536,6 +545,7 @@ class CompilationStateImpl {
|
||||
int outstanding_top_tier_functions_ = 0;
|
||||
std::vector<uint8_t> compilation_progress_;
|
||||
|
||||
int outstanding_recompilation_functions_ = 0;
|
||||
// End of fields protected by {callbacks_mutex_}.
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@ -597,6 +607,10 @@ bool CompilationState::top_tier_compilation_finished() const {
|
||||
return Impl(this)->top_tier_compilation_finished();
|
||||
}
|
||||
|
||||
bool CompilationState::recompilation_finished() const {
|
||||
return Impl(this)->recompilation_finished();
|
||||
}
|
||||
|
||||
// static
|
||||
std::unique_ptr<CompilationState> CompilationState::New(
|
||||
const std::shared_ptr<NativeModule>& native_module,
|
||||
@ -747,6 +761,10 @@ class CompilationUnitBuilder {
|
||||
tiering_units_.emplace_back(func_index, tiers.top_tier);
|
||||
}
|
||||
|
||||
void AddBaselineUnit(int func_index) {
|
||||
baseline_units_.emplace_back(func_index, ExecutionTier::kLiftoff);
|
||||
}
|
||||
|
||||
bool Commit() {
|
||||
if (baseline_units_.empty() && tiering_units_.empty() &&
|
||||
js_to_wasm_wrapper_units_.empty()) {
|
||||
@ -1195,6 +1213,19 @@ void InitializeCompilationUnits(Isolate* isolate, NativeModule* native_module) {
|
||||
builder.Commit();
|
||||
}
|
||||
|
||||
void AddBaselineCompilationUnits(NativeModule* native_module) {
|
||||
CompilationUnitBuilder builder(native_module);
|
||||
auto* module = native_module->module();
|
||||
|
||||
uint32_t start = module->num_imported_functions;
|
||||
uint32_t end = start + module->num_declared_functions;
|
||||
for (uint32_t func_index = start; func_index < end; func_index++) {
|
||||
builder.AddBaselineUnit(func_index);
|
||||
}
|
||||
|
||||
builder.Commit();
|
||||
}
|
||||
|
||||
bool MayCompriseLazyFunctions(const WasmModule* module,
|
||||
const WasmFeatures& enabled_features,
|
||||
bool lazy_module) {
|
||||
@ -1388,6 +1419,40 @@ std::shared_ptr<NativeModule> CompileToNativeModule(
|
||||
return native_module;
|
||||
}
|
||||
|
||||
void RecompileNativeModule(Isolate* isolate, NativeModule* native_module,
|
||||
ExecutionTier tier) {
|
||||
// Install a callback to notify us once background recompilation finished.
|
||||
auto recompilation_finished_semaphore = std::make_shared<base::Semaphore>(0);
|
||||
auto* compilation_state = Impl(native_module->compilation_state());
|
||||
DCHECK_EQ(tier, ExecutionTier::kLiftoff);
|
||||
// The callback captures a shared ptr to the semaphore.
|
||||
compilation_state->AddCallback(
|
||||
[recompilation_finished_semaphore](CompilationEvent event) {
|
||||
if (event == CompilationEvent::kFinishedRecompilation) {
|
||||
recompilation_finished_semaphore->Signal();
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize the compilation units and kick off background compile tasks.
|
||||
compilation_state->InitializeRecompilationProgress(tier);
|
||||
AddBaselineCompilationUnits(native_module);
|
||||
|
||||
// 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.
|
||||
}
|
||||
}
|
||||
|
||||
// Now wait until baseline recompilation finished.
|
||||
recompilation_finished_semaphore->Wait();
|
||||
DCHECK(!compilation_state->failed());
|
||||
}
|
||||
|
||||
AsyncCompileJob::AsyncCompileJob(
|
||||
Isolate* isolate, const WasmFeatures& enabled,
|
||||
std::unique_ptr<byte[]> bytes_copy, size_t length, Handle<Context> context,
|
||||
@ -1630,7 +1695,7 @@ class AsyncCompileJob::CompilationStateCallback {
|
||||
// At this point, the job will already be gone, thus do not access it
|
||||
// here.
|
||||
break;
|
||||
case CompilationEvent::kFailedCompilation: {
|
||||
case CompilationEvent::kFailedCompilation:
|
||||
DCHECK(!last_event_.has_value());
|
||||
if (job_->DecrementAndCheckFinisherCount()) {
|
||||
// TODO(v8:6847): Also share streaming compilation result.
|
||||
@ -1641,7 +1706,8 @@ class AsyncCompileJob::CompilationStateCallback {
|
||||
job_->DoSync<CompileFailed>();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CompilationEvent::kFinishedRecompilation:
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
@ -1960,6 +2026,7 @@ class SampleTopTierCodeSizeCallback {
|
||||
void operator()(CompilationEvent event) {
|
||||
// This callback is registered after baseline compilation finished, so the
|
||||
// only possible event to follow is {kFinishedTopTierCompilation}.
|
||||
if (event == CompilationEvent::kFinishedRecompilation) return;
|
||||
DCHECK_EQ(CompilationEvent::kFinishedTopTierCompilation, event);
|
||||
if (std::shared_ptr<NativeModule> native_module = native_module_.lock()) {
|
||||
native_module->engine()->SampleTopTierCodeSizeInAllIsolates(
|
||||
@ -2352,6 +2419,37 @@ void CompilationStateImpl::InitializeCompilationProgress(bool lazy_module,
|
||||
}
|
||||
}
|
||||
|
||||
void CompilationStateImpl::InitializeRecompilationProgress(ExecutionTier tier) {
|
||||
DCHECK(!failed());
|
||||
auto* module = native_module_->module();
|
||||
|
||||
base::MutexGuard guard(&callbacks_mutex_);
|
||||
// Ensure that we don't trigger recompilation if another recompilation is
|
||||
// already happening.
|
||||
DCHECK_EQ(0, outstanding_recompilation_functions_);
|
||||
int start = module->num_imported_functions;
|
||||
int end = start + module->num_declared_functions;
|
||||
for (int function_index = start; function_index < end; function_index++) {
|
||||
int slot_index = function_index - start;
|
||||
DCHECK_LT(slot_index, compilation_progress_.size());
|
||||
ExecutionTier reached_tier =
|
||||
ReachedTierField::decode(compilation_progress_[slot_index]);
|
||||
if (reached_tier != tier) {
|
||||
outstanding_recompilation_functions_++;
|
||||
}
|
||||
}
|
||||
DCHECK_LE(0, outstanding_recompilation_functions_);
|
||||
DCHECK_LE(outstanding_recompilation_functions_,
|
||||
module->num_declared_functions);
|
||||
|
||||
// Trigger callbacks if module needs no recompilation.
|
||||
if (outstanding_recompilation_functions_ == 0) {
|
||||
for (auto& callback : callbacks_) {
|
||||
callback(CompilationEvent::kFinishedRecompilation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CompilationStateImpl::AddCallback(CompilationState::callback_t callback) {
|
||||
base::MutexGuard callbacks_guard(&callbacks_mutex_);
|
||||
callbacks_.emplace_back(std::move(callback));
|
||||
@ -2423,7 +2521,8 @@ void CompilationStateImpl::OnFinishedUnits(Vector<WasmCode*> code_vector) {
|
||||
// This is especially important for lazy modules that were deserialized.
|
||||
// Compilation progress was not set up in these cases.
|
||||
if (outstanding_baseline_units_ == 0 &&
|
||||
outstanding_top_tier_functions_ == 0) {
|
||||
outstanding_top_tier_functions_ == 0 &&
|
||||
outstanding_recompilation_functions_ == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2439,6 +2538,7 @@ void CompilationStateImpl::OnFinishedUnits(Vector<WasmCode*> code_vector) {
|
||||
|
||||
bool completes_baseline_compilation = false;
|
||||
bool completes_top_tier_compilation = false;
|
||||
bool completes_recompilation = false;
|
||||
|
||||
for (WasmCode* code : code_vector) {
|
||||
DCHECK_NOT_NULL(code);
|
||||
@ -2486,17 +2586,34 @@ void CompilationStateImpl::OnFinishedUnits(Vector<WasmCode*> code_vector) {
|
||||
}
|
||||
}
|
||||
|
||||
// Update function's compilation progress.
|
||||
if (code->tier() > reached_tier) {
|
||||
compilation_progress_[slot_index] = ReachedTierField::update(
|
||||
compilation_progress_[slot_index], code->tier());
|
||||
// If there is recompilation in progress, we would only count the
|
||||
// functions which are not Liftoff already, and would only decrement the
|
||||
// counter once a function reaches Liftoff.
|
||||
if (outstanding_recompilation_functions_ > 0) {
|
||||
// TODO(duongn): extend this logic for tier up.
|
||||
if (code->tier() == ExecutionTier::kLiftoff &&
|
||||
reached_tier != ExecutionTier::kLiftoff) {
|
||||
outstanding_recompilation_functions_--;
|
||||
// Update function's compilation progress.
|
||||
compilation_progress_[slot_index] = ReachedTierField::update(
|
||||
compilation_progress_[slot_index], code->tier());
|
||||
if (outstanding_recompilation_functions_ == 0) {
|
||||
completes_recompilation = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Update function's compilation progress.
|
||||
if (code->tier() > reached_tier) {
|
||||
compilation_progress_[slot_index] = ReachedTierField::update(
|
||||
compilation_progress_[slot_index], code->tier());
|
||||
}
|
||||
}
|
||||
DCHECK_LE(0, outstanding_baseline_units_);
|
||||
}
|
||||
}
|
||||
|
||||
TriggerCallbacks(completes_baseline_compilation,
|
||||
completes_top_tier_compilation);
|
||||
completes_top_tier_compilation, completes_recompilation);
|
||||
}
|
||||
|
||||
void CompilationStateImpl::OnFinishedJSToWasmWrapperUnits(int num) {
|
||||
@ -2507,8 +2624,14 @@ void CompilationStateImpl::OnFinishedJSToWasmWrapperUnits(int num) {
|
||||
TriggerCallbacks(completes_baseline_compilation, false);
|
||||
}
|
||||
|
||||
void CompilationStateImpl::TriggerCallbacks(
|
||||
bool completes_baseline_compilation, bool completes_top_tier_compilation) {
|
||||
void CompilationStateImpl::TriggerCallbacks(bool completes_baseline_compilation,
|
||||
bool completes_top_tier_compilation,
|
||||
bool completes_recompilation) {
|
||||
if (completes_recompilation) {
|
||||
for (auto& callback : callbacks_) {
|
||||
callback(CompilationEvent::kFinishedRecompilation);
|
||||
}
|
||||
}
|
||||
if (completes_baseline_compilation) {
|
||||
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"), "BaselineFinished");
|
||||
for (auto& callback : callbacks_) {
|
||||
@ -2523,6 +2646,10 @@ void CompilationStateImpl::TriggerCallbacks(
|
||||
for (auto& callback : callbacks_) {
|
||||
callback(CompilationEvent::kFinishedTopTierCompilation);
|
||||
}
|
||||
}
|
||||
if (outstanding_baseline_units_ == 0 &&
|
||||
outstanding_top_tier_functions_ == 0 &&
|
||||
outstanding_recompilation_functions_ == 0) {
|
||||
// Clear the callbacks because no more events will be delivered.
|
||||
callbacks_.clear();
|
||||
}
|
||||
@ -2589,7 +2716,7 @@ void CompilationStateImpl::RestartBackgroundTasks() {
|
||||
}
|
||||
}
|
||||
|
||||
if (baseline_compilation_finished()) {
|
||||
if (baseline_compilation_finished() && recompilation_finished()) {
|
||||
for (auto& task : new_tasks) {
|
||||
V8::GetCurrentPlatform()->CallLowPriorityTaskOnWorkerThread(
|
||||
std::move(task));
|
||||
|
@ -44,6 +44,9 @@ std::shared_ptr<NativeModule> CompileToNativeModule(
|
||||
std::shared_ptr<const WasmModule> module, const ModuleWireBytes& wire_bytes,
|
||||
Handle<FixedArray>* export_wrappers_out);
|
||||
|
||||
void RecompileNativeModule(Isolate* isolate, NativeModule* native_module,
|
||||
ExecutionTier tier);
|
||||
|
||||
V8_EXPORT_PRIVATE
|
||||
void CompileJsToWasmWrappers(Isolate* isolate, const WasmModule* module,
|
||||
Handle<FixedArray>* export_wrappers_out);
|
||||
|
@ -1818,13 +1818,8 @@ void NativeModule::TierDown(Isolate* isolate) {
|
||||
tier_down_ = true;
|
||||
}
|
||||
// Tier down all functions.
|
||||
// TODO(duongn): parallelize this eventually.
|
||||
for (uint32_t index = module_->num_imported_functions;
|
||||
index < num_functions(); index++) {
|
||||
isolate->wasm_engine()->CompileFunction(isolate, this, index,
|
||||
ExecutionTier::kLiftoff);
|
||||
DCHECK(!compilation_state()->failed());
|
||||
}
|
||||
isolate->wasm_engine()->RecompileAllFunctions(isolate, this,
|
||||
ExecutionTier::kLiftoff);
|
||||
}
|
||||
|
||||
void NativeModule::TierUp(Isolate* isolate) {
|
||||
|
@ -488,6 +488,12 @@ void WasmEngine::CompileFunction(Isolate* isolate, NativeModule* native_module,
|
||||
&native_module->module()->functions[function_index], tier);
|
||||
}
|
||||
|
||||
void WasmEngine::RecompileAllFunctions(Isolate* isolate,
|
||||
NativeModule* native_module,
|
||||
ExecutionTier tier) {
|
||||
RecompileNativeModule(isolate, native_module, tier);
|
||||
}
|
||||
|
||||
std::shared_ptr<NativeModule> WasmEngine::ExportNativeModule(
|
||||
Handle<WasmModuleObject> module_object) {
|
||||
return module_object->shared_native_module();
|
||||
|
@ -148,6 +148,10 @@ class V8_EXPORT_PRIVATE WasmEngine {
|
||||
void CompileFunction(Isolate* isolate, NativeModule* native_module,
|
||||
uint32_t function_index, ExecutionTier tier);
|
||||
|
||||
// Recompiles all functions at a specific compilation tier.
|
||||
void RecompileAllFunctions(Isolate* isolate, NativeModule* native_module,
|
||||
ExecutionTier tier);
|
||||
|
||||
// Exports the sharable parts of the given module object so that they can be
|
||||
// transferred to a different Context/Isolate using the same engine.
|
||||
std::shared_ptr<NativeModule> ExportNativeModule(
|
||||
|
@ -2,17 +2,17 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --allow-natives-syntax --wasm-tier-up
|
||||
// Flags: --allow-natives-syntax --liftoff --wasm-tier-up --no-stress-opt
|
||||
|
||||
load('test/mjsunit/wasm/wasm-module-builder.js');
|
||||
|
||||
const num_functions = 2;
|
||||
|
||||
function create_builder() {
|
||||
function create_builder(delta = 0) {
|
||||
const builder = new WasmModuleBuilder();
|
||||
for (let i = 0; i < num_functions; ++i) {
|
||||
builder.addFunction('f' + i, kSig_i_v)
|
||||
.addBody(wasmI32Const(i))
|
||||
.addBody(wasmI32Const(i + delta))
|
||||
.exportFunc();
|
||||
}
|
||||
return builder;
|
||||
@ -41,10 +41,10 @@ function check(instance) {
|
||||
check(instance);
|
||||
})();
|
||||
|
||||
|
||||
// Use slightly different module for this test to avoid sharing native module.
|
||||
async function testTierDownToLiftoffAsync() {
|
||||
print(arguments.callee.name);
|
||||
const instance = await create_builder().asyncInstantiate();
|
||||
const instance = await create_builder(num_functions).asyncInstantiate();
|
||||
check(instance);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user