Commit 0dc598df authored by Clemens Backes's avatar Clemens Backes Committed by Commit Bot

[wasm] Refactor callback triggering

1) Instead of passing three boolean values to |TriggerCallbacks|, pass
   one EnumSet which contains all events to trigger.
2) Remember which events already happened, to avoid triggering them
   again.
3) Compute triggered events once after the loop in |OnFinishedUnits|,
   instead of checking for every finished unit.
4) When a new callback is registered, trigger all previous events
   immediately. This solves issue v8:10217.
5) Replace |NotifyTopTierReady| by |AddCallback| which is identical now.
6) Do not call |OnFinishedJSToWasmWrapperUnits| if no wrappers were
   compiled (this is a minor performance optimization; we save taking
   and releasing a lock).
7) Drive-by: Make the |EnumSet| constructor really constexpr (by making
   |Mask| constexpr).

R=ahaas@chromium.org

Bug: v8:10217
Change-Id: Ib3688a1687ad7b523e90efd73f4073e9f1193016
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2072737
Commit-Queue: Clemens Backes <clemensb@chromium.org>
Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#66459}
parent 14524a20
...@@ -62,8 +62,10 @@ class EnumSet { ...@@ -62,8 +62,10 @@ class EnumSet {
private: private:
explicit constexpr EnumSet(T bits) : bits_(bits) {} explicit constexpr EnumSet(T bits) : bits_(bits) {}
static T Mask(E element) { static constexpr T Mask(E element) {
#if V8_HAS_CXX14_CONSTEXPR
DCHECK_GT(sizeof(T) * 8, static_cast<int>(element)); DCHECK_GT(sizeof(T) * 8, static_cast<int>(element));
#endif
return T{1} << static_cast<typename std::underlying_type<E>::type>(element); return T{1} << static_cast<typename std::underlying_type<E>::type>(element);
} }
......
...@@ -119,7 +119,6 @@ class CompilationState { ...@@ -119,7 +119,6 @@ class CompilationState {
const; const;
void AddCallback(callback_t); void AddCallback(callback_t);
void NotifyTopTierReady(callback_t);
bool failed() const; bool failed() const;
V8_EXPORT_PRIVATE bool baseline_compilation_finished() const; V8_EXPORT_PRIVATE bool baseline_compilation_finished() const;
......
...@@ -394,10 +394,6 @@ class CompilationStateImpl { ...@@ -394,10 +394,6 @@ class CompilationStateImpl {
// events. The callback object must support being deleted from any thread. // events. The callback object must support being deleted from any thread.
void AddCallback(CompilationState::callback_t); void AddCallback(CompilationState::callback_t);
// If the module is already tiered up, trigger the callback immediately with a
// {kFinishedTopTierCompilation} event. Otherwise, behave as {AddCallback}.
void NotifyTopTierReady(CompilationState::callback_t);
// Inserts new functions to compile and kicks off compilation. // Inserts new functions to compile and kicks off compilation.
void AddCompilationUnits( void AddCompilationUnits(
Vector<WasmCompilationUnit> baseline_units, Vector<WasmCompilationUnit> baseline_units,
...@@ -415,9 +411,7 @@ class CompilationStateImpl { ...@@ -415,9 +411,7 @@ class CompilationStateImpl {
void OnFinishedUnits(Vector<WasmCode*>, Vector<WasmCompilationResult>); void OnFinishedUnits(Vector<WasmCode*>, Vector<WasmCompilationResult>);
void OnFinishedJSToWasmWrapperUnits(int num); void OnFinishedJSToWasmWrapperUnits(int num);
void TriggerCallbacks(bool completes_baseline_compilation, void TriggerCallbacks(base::EnumSet<CompilationEvent>);
bool completes_top_tier_compilation,
bool completes_recompilation = false);
void OnBackgroundTaskStopped(int task_id, const WasmFeatures& detected); void OnBackgroundTaskStopped(int task_id, const WasmFeatures& detected);
void UpdateDetectedFeatures(const WasmFeatures& detected); void UpdateDetectedFeatures(const WasmFeatures& detected);
...@@ -550,6 +544,9 @@ class CompilationStateImpl { ...@@ -550,6 +544,9 @@ class CompilationStateImpl {
// Callback functions to be called on compilation events. // Callback functions to be called on compilation events.
std::vector<CompilationState::callback_t> callbacks_; std::vector<CompilationState::callback_t> callbacks_;
// Events that already happened.
base::EnumSet<CompilationEvent> finished_events_;
int outstanding_baseline_units_ = 0; int outstanding_baseline_units_ = 0;
int outstanding_top_tier_functions_ = 0; int outstanding_top_tier_functions_ = 0;
std::vector<uint8_t> compilation_progress_; std::vector<uint8_t> compilation_progress_;
...@@ -607,11 +604,6 @@ void CompilationState::AddCallback(CompilationState::callback_t callback) { ...@@ -607,11 +604,6 @@ void CompilationState::AddCallback(CompilationState::callback_t callback) {
return Impl(this)->AddCallback(std::move(callback)); return Impl(this)->AddCallback(std::move(callback));
} }
void CompilationState::NotifyTopTierReady(
CompilationState::callback_t callback) {
return Impl(this)->NotifyTopTierReady(std::move(callback));
}
bool CompilationState::failed() const { return Impl(this)->failed(); } bool CompilationState::failed() const { return Impl(this)->failed(); }
bool CompilationState::baseline_compilation_finished() const { bool CompilationState::baseline_compilation_finished() const {
...@@ -985,7 +977,7 @@ bool ExecuteJSToWasmWrapperCompilationUnits( ...@@ -985,7 +977,7 @@ bool ExecuteJSToWasmWrapperCompilationUnits(
++num_processed_wrappers; ++num_processed_wrappers;
} }
} while (wrapper_unit); } while (wrapper_unit);
{ if (num_processed_wrappers > 0) {
BackgroundCompileScope compile_scope(token); BackgroundCompileScope compile_scope(token);
if (compile_scope.cancelled()) return false; if (compile_scope.cancelled()) return false;
compile_scope.compilation_state()->OnFinishedJSToWasmWrapperUnits( compile_scope.compilation_state()->OnFinishedJSToWasmWrapperUnits(
...@@ -2054,10 +2046,7 @@ class SampleTopTierCodeSizeCallback { ...@@ -2054,10 +2046,7 @@ class SampleTopTierCodeSizeCallback {
: native_module_(std::move(native_module)) {} : native_module_(std::move(native_module)) {}
void operator()(CompilationEvent event) { void operator()(CompilationEvent event) {
// This callback is registered after baseline compilation finished, so the if (event != CompilationEvent::kFinishedTopTierCompilation) return;
// 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()) { if (std::shared_ptr<NativeModule> native_module = native_module_.lock()) {
native_module->engine()->SampleTopTierCodeSizeInAllIsolates( native_module->engine()->SampleTopTierCodeSizeInAllIsolates(
native_module); native_module);
...@@ -2582,17 +2571,20 @@ void CompilationStateImpl::InitializeRecompilation( ...@@ -2582,17 +2571,20 @@ void CompilationStateImpl::InitializeRecompilation(
void CompilationStateImpl::AddCallback(CompilationState::callback_t callback) { void CompilationStateImpl::AddCallback(CompilationState::callback_t callback) {
base::MutexGuard callbacks_guard(&callbacks_mutex_); base::MutexGuard callbacks_guard(&callbacks_mutex_);
// Immediately trigger events that already happened.
for (auto event : {CompilationEvent::kFinishedBaselineCompilation,
CompilationEvent::kFinishedTopTierCompilation,
CompilationEvent::kFailedCompilation}) {
if (finished_events_.contains(event)) {
callback(event);
}
}
constexpr base::EnumSet<CompilationEvent> kFinalEvents{
CompilationEvent::kFinishedTopTierCompilation,
CompilationEvent::kFailedCompilation};
if (!finished_events_.contains_any(kFinalEvents)) {
callbacks_.emplace_back(std::move(callback)); callbacks_.emplace_back(std::move(callback));
}
void CompilationStateImpl::NotifyTopTierReady(
CompilationState::callback_t callback) {
base::MutexGuard callbacks_guard(&callbacks_mutex_);
if (!compilation_progress_.empty() && outstanding_top_tier_functions_ == 0) {
callback(CompilationEvent::kFinishedTopTierCompilation);
return;
} }
callbacks_.emplace_back(std::move(callback));
} }
void CompilationStateImpl::AddCompilationUnits( void CompilationStateImpl::AddCompilationUnits(
...@@ -2677,9 +2669,7 @@ void CompilationStateImpl::OnFinishedUnits( ...@@ -2677,9 +2669,7 @@ void CompilationStateImpl::OnFinishedUnits(
DCHECK_EQ(compilation_progress_.size(), DCHECK_EQ(compilation_progress_.size(),
native_module_->module()->num_declared_functions); native_module_->module()->num_declared_functions);
bool completes_baseline_compilation = false; base::EnumSet<CompilationEvent> triggered_events;
bool completes_top_tier_compilation = false;
bool completes_recompilation = false;
for (size_t i = 0; i < code_vector.size(); i++) { for (size_t i = 0; i < code_vector.size(); i++) {
WasmCode* code = code_vector[i]; WasmCode* code = code_vector[i];
...@@ -2690,9 +2680,6 @@ void CompilationStateImpl::OnFinishedUnits( ...@@ -2690,9 +2680,6 @@ void CompilationStateImpl::OnFinishedUnits(
// Import wrapper. // Import wrapper.
DCHECK_EQ(code->tier(), ExecutionTier::kTurbofan); DCHECK_EQ(code->tier(), ExecutionTier::kTurbofan);
outstanding_baseline_units_--; outstanding_baseline_units_--;
if (outstanding_baseline_units_ == 0) {
completes_baseline_compilation = true;
}
} else { } else {
// Function. // Function.
DCHECK_NE(code->tier(), ExecutionTier::kNone); DCHECK_NE(code->tier(), ExecutionTier::kNone);
...@@ -2715,17 +2702,11 @@ void CompilationStateImpl::OnFinishedUnits( ...@@ -2715,17 +2702,11 @@ void CompilationStateImpl::OnFinishedUnits(
required_baseline_tier <= code->tier()) { required_baseline_tier <= code->tier()) {
DCHECK_GT(outstanding_baseline_units_, 0); DCHECK_GT(outstanding_baseline_units_, 0);
outstanding_baseline_units_--; outstanding_baseline_units_--;
if (outstanding_baseline_units_ == 0) {
completes_baseline_compilation = true;
}
} }
if (reached_tier < required_top_tier && if (reached_tier < required_top_tier &&
required_top_tier <= code->tier()) { required_top_tier <= code->tier()) {
DCHECK_GT(outstanding_top_tier_functions_, 0); DCHECK_GT(outstanding_top_tier_functions_, 0);
outstanding_top_tier_functions_--; outstanding_top_tier_functions_--;
if (outstanding_top_tier_functions_ == 0) {
completes_top_tier_compilation = true;
}
} }
// If there is recompilation in progress, we would only count the // If there is recompilation in progress, we would only count the
...@@ -2744,7 +2725,7 @@ void CompilationStateImpl::OnFinishedUnits( ...@@ -2744,7 +2725,7 @@ void CompilationStateImpl::OnFinishedUnits(
ReachedRecompilationTierField::update( ReachedRecompilationTierField::update(
compilation_progress_[slot_index], code->tier()); compilation_progress_[slot_index], code->tier());
if (outstanding_recompilation_functions_ == 0) { if (outstanding_recompilation_functions_ == 0) {
completes_recompilation = true; triggered_events.Add(CompilationEvent::kFinishedRecompilation);
} }
} }
} }
...@@ -2758,43 +2739,51 @@ void CompilationStateImpl::OnFinishedUnits( ...@@ -2758,43 +2739,51 @@ void CompilationStateImpl::OnFinishedUnits(
} }
} }
TriggerCallbacks(completes_baseline_compilation, if (outstanding_baseline_units_ == 0) {
completes_top_tier_compilation, completes_recompilation); triggered_events.Add(CompilationEvent::kFinishedBaselineCompilation);
if (outstanding_top_tier_functions_ == 0) {
triggered_events.Add(CompilationEvent::kFinishedTopTierCompilation);
}
}
if (!triggered_events.empty()) TriggerCallbacks(triggered_events);
} }
void CompilationStateImpl::OnFinishedJSToWasmWrapperUnits(int num) { void CompilationStateImpl::OnFinishedJSToWasmWrapperUnits(int num) {
if (num == 0) return; if (num == 0) return;
base::MutexGuard guard(&callbacks_mutex_); base::MutexGuard guard(&callbacks_mutex_);
DCHECK_GE(outstanding_baseline_units_, num);
outstanding_baseline_units_ -= num; outstanding_baseline_units_ -= num;
bool completes_baseline_compilation = outstanding_baseline_units_ == 0; if (outstanding_baseline_units_ == 0) {
TriggerCallbacks(completes_baseline_compilation, false); TriggerCallbacks(base::EnumSet<CompilationEvent>{
CompilationEvent::kFinishedBaselineCompilation});
}
} }
void CompilationStateImpl::TriggerCallbacks(bool completes_baseline_compilation, void CompilationStateImpl::TriggerCallbacks(
bool completes_top_tier_compilation, base::EnumSet<CompilationEvent> triggered_events) {
bool completes_recompilation) {
DCHECK(!callbacks_mutex_.TryLock()); DCHECK(!callbacks_mutex_.TryLock());
if (completes_recompilation) {
DCHECK(!callbacks_.empty()); // Don't trigger past events again.
for (auto& callback : callbacks_) { triggered_events -= finished_events_;
callback(CompilationEvent::kFinishedRecompilation); // Recompilation can happen multiple times, thus do not store this.
} finished_events_ |=
} triggered_events - CompilationEvent::kFinishedRecompilation;
if (completes_baseline_compilation) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"), "BaselineFinished"); for (auto event :
for (auto& callback : callbacks_) { {std::make_pair(CompilationEvent::kFinishedBaselineCompilation,
callback(CompilationEvent::kFinishedBaselineCompilation); "BaselineFinished"),
} std::make_pair(CompilationEvent::kFinishedTopTierCompilation,
if (outstanding_top_tier_functions_ == 0) { "TopTierFinished"),
completes_top_tier_compilation = true; std::make_pair(CompilationEvent::kFinishedRecompilation,
} "RecompilationFinished")}) {
} if (!triggered_events.contains(event.first)) continue;
if (outstanding_baseline_units_ == 0 && completes_top_tier_compilation) { TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"), event.second);
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"), "TopTierFinished");
for (auto& callback : callbacks_) { for (auto& callback : callbacks_) {
callback(CompilationEvent::kFinishedTopTierCompilation); callback(event.first);
} }
} }
if (outstanding_baseline_units_ == 0 && if (outstanding_baseline_units_ == 0 &&
outstanding_top_tier_functions_ == 0 && outstanding_top_tier_functions_ == 0 &&
outstanding_recompilation_functions_ == 0) { outstanding_recompilation_functions_ == 0) {
......
...@@ -154,7 +154,7 @@ void StreamingDecoder::NotifyNativeModuleCreated( ...@@ -154,7 +154,7 @@ void StreamingDecoder::NotifyNativeModuleCreated(
const std::shared_ptr<NativeModule>& native_module) { const std::shared_ptr<NativeModule>& native_module) {
if (!module_compiled_callback_) return; if (!module_compiled_callback_) return;
auto* comp_state = native_module->compilation_state(); auto* comp_state = native_module->compilation_state();
comp_state->NotifyTopTierReady(TopTierCompiledCallback{ comp_state->AddCallback(TopTierCompiledCallback{
std::move(native_module), std::move(module_compiled_callback_)}); std::move(native_module), std::move(module_compiled_callback_)});
module_compiled_callback_ = {}; module_compiled_callback_ = {};
} }
......
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