[wasm][gc] Track number of GCs triggered per module
We currently have the problem that we trigger too many code GCs since {new_potentially_dead_code_size_} is never reset to zero. This CL adds a counter which tells us how many GCs we ran per native module. This counter is sampled on each code GC. It will give us a good understanding of the amount of GC work we are executing in the wild. The number should stay in the single-digits generally. R=mstarzinger@chromium.org, mpearson@chromium.org Bug: v8:8217 Change-Id: I978a98dff76e0f466ff51e067626886b58d52ded Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1615246 Reviewed-by: Michael Starzinger <mstarzinger@chromium.org> Commit-Queue: Clemens Hammacher <clemensh@chromium.org> Cr-Commit-Position: refs/heads/master@{#61611}
This commit is contained in:
parent
72200ddef4
commit
429ee454e2
@ -86,7 +86,10 @@ namespace internal {
|
|||||||
HR(wasm_module_freed_code_size_mb, V8.WasmModuleCodeSizeFreed, 0, 1024, 64) \
|
HR(wasm_module_freed_code_size_mb, V8.WasmModuleCodeSizeFreed, 0, 1024, 64) \
|
||||||
/* percent of freed code size per module, collected on GC */ \
|
/* percent of freed code size per module, collected on GC */ \
|
||||||
HR(wasm_module_freed_code_size_percent, V8.WasmModuleCodeSizePercentFreed, \
|
HR(wasm_module_freed_code_size_percent, V8.WasmModuleCodeSizePercentFreed, \
|
||||||
0, 100, 32)
|
0, 100, 32) \
|
||||||
|
/* number of code GCs triggered per native module, collected on code GC */ \
|
||||||
|
HR(wasm_module_num_triggered_code_gcs, \
|
||||||
|
V8.WasmModuleNumberOfCodeGCsTriggered, 1, 128, 20)
|
||||||
|
|
||||||
#define HISTOGRAM_TIMER_LIST(HT) \
|
#define HISTOGRAM_TIMER_LIST(HT) \
|
||||||
/* Timer histograms, not thread safe: HT(name, caption, max, unit) */ \
|
/* Timer histograms, not thread safe: HT(name, caption, max, unit) */ \
|
||||||
|
@ -115,6 +115,11 @@ class WasmGCForegroundTask : public Task {
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
struct WasmEngine::CurrentGCInfo {
|
struct WasmEngine::CurrentGCInfo {
|
||||||
|
explicit CurrentGCInfo(int8_t gc_sequence_index)
|
||||||
|
: gc_sequence_index(gc_sequence_index) {
|
||||||
|
DCHECK_NE(0, gc_sequence_index);
|
||||||
|
}
|
||||||
|
|
||||||
// Set of isolates that did not scan their stack yet for used WasmCode, and
|
// Set of isolates that did not scan their stack yet for used WasmCode, and
|
||||||
// their scheduled foreground task.
|
// their scheduled foreground task.
|
||||||
std::unordered_map<Isolate*, WasmGCForegroundTask*> outstanding_isolates;
|
std::unordered_map<Isolate*, WasmGCForegroundTask*> outstanding_isolates;
|
||||||
@ -123,10 +128,17 @@ struct WasmEngine::CurrentGCInfo {
|
|||||||
// Code that is still in-use is removed by the individual isolates.
|
// Code that is still in-use is removed by the individual isolates.
|
||||||
std::unordered_set<WasmCode*> dead_code;
|
std::unordered_set<WasmCode*> dead_code;
|
||||||
|
|
||||||
|
// The number of GCs triggered in the native module that triggered this GC.
|
||||||
|
// This is stored in the histogram for each participating isolate during
|
||||||
|
// execution of that isolate's foreground task.
|
||||||
|
const int8_t gc_sequence_index;
|
||||||
|
|
||||||
// If during this GC, another GC was requested, we skipped that other GC (we
|
// If during this GC, another GC was requested, we skipped that other GC (we
|
||||||
// only run one GC at a time). Remember though to trigger another one once
|
// only run one GC at a time). Remember though to trigger another one once
|
||||||
// this one finishes.
|
// this one finishes. {next_gc_sequence_index} is 0 if no next GC is needed,
|
||||||
bool run_another_gc = false;
|
// and >0 otherwise. It stores the {num_code_gcs_triggered} of the native
|
||||||
|
// module which triggered the next GC.
|
||||||
|
int8_t next_gc_sequence_index = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct WasmEngine::IsolateInfo {
|
struct WasmEngine::IsolateInfo {
|
||||||
@ -175,6 +187,10 @@ struct WasmEngine::NativeModuleInfo {
|
|||||||
// Code that is not being executed in any isolate any more, but the ref count
|
// Code that is not being executed in any isolate any more, but the ref count
|
||||||
// did not drop to zero yet.
|
// did not drop to zero yet.
|
||||||
std::unordered_set<WasmCode*> dead_code;
|
std::unordered_set<WasmCode*> dead_code;
|
||||||
|
|
||||||
|
// Number of code GCs triggered because code in this native module became
|
||||||
|
// potentially dead.
|
||||||
|
int8_t num_code_gcs_triggered = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
WasmEngine::WasmEngine()
|
WasmEngine::WasmEngine()
|
||||||
@ -704,6 +720,8 @@ void WasmEngine::ReportLiveCodeForGC(Isolate* isolate,
|
|||||||
// a foreground task). In that case, ignore it.
|
// a foreground task). In that case, ignore it.
|
||||||
if (current_gc_info_ == nullptr) return;
|
if (current_gc_info_ == nullptr) return;
|
||||||
if (!RemoveIsolateFromCurrentGC(isolate)) return;
|
if (!RemoveIsolateFromCurrentGC(isolate)) return;
|
||||||
|
isolate->counters()->wasm_module_num_triggered_code_gcs()->AddSample(
|
||||||
|
current_gc_info_->gc_sequence_index);
|
||||||
for (WasmCode* code : live_code) current_gc_info_->dead_code.erase(code);
|
for (WasmCode* code : live_code) current_gc_info_->dead_code.erase(code);
|
||||||
PotentiallyFinishCurrentGC();
|
PotentiallyFinishCurrentGC();
|
||||||
}
|
}
|
||||||
@ -725,8 +743,9 @@ bool WasmEngine::AddPotentiallyDeadCode(WasmCode* code) {
|
|||||||
base::MutexGuard guard(&mutex_);
|
base::MutexGuard guard(&mutex_);
|
||||||
auto it = native_modules_.find(code->native_module());
|
auto it = native_modules_.find(code->native_module());
|
||||||
DCHECK_NE(native_modules_.end(), it);
|
DCHECK_NE(native_modules_.end(), it);
|
||||||
if (it->second->dead_code.count(code)) return false; // Code is already dead.
|
NativeModuleInfo* info = it->second.get();
|
||||||
auto added = it->second->potentially_dead_code.insert(code);
|
if (info->dead_code.count(code)) return false; // Code is already dead.
|
||||||
|
auto added = info->potentially_dead_code.insert(code);
|
||||||
if (!added.second) return false; // An entry already existed.
|
if (!added.second) return false; // An entry already existed.
|
||||||
new_potentially_dead_code_size_ += code->instructions().size();
|
new_potentially_dead_code_size_ += code->instructions().size();
|
||||||
if (FLAG_wasm_code_gc) {
|
if (FLAG_wasm_code_gc) {
|
||||||
@ -736,17 +755,22 @@ bool WasmEngine::AddPotentiallyDeadCode(WasmCode* code) {
|
|||||||
? 0
|
? 0
|
||||||
: 1 * MB + code_manager_.committed_code_space() / 10;
|
: 1 * MB + code_manager_.committed_code_space() / 10;
|
||||||
if (new_potentially_dead_code_size_ > dead_code_limit) {
|
if (new_potentially_dead_code_size_ > dead_code_limit) {
|
||||||
|
bool inc_gc_count =
|
||||||
|
info->num_code_gcs_triggered < std::numeric_limits<int8_t>::max();
|
||||||
if (current_gc_info_ == nullptr) {
|
if (current_gc_info_ == nullptr) {
|
||||||
|
if (inc_gc_count) ++info->num_code_gcs_triggered;
|
||||||
TRACE_CODE_GC(
|
TRACE_CODE_GC(
|
||||||
"Triggering GC (potentially dead: %zu bytes; limit: %zu bytes).\n",
|
"Triggering GC (potentially dead: %zu bytes; limit: %zu bytes).\n",
|
||||||
new_potentially_dead_code_size_, dead_code_limit);
|
new_potentially_dead_code_size_, dead_code_limit);
|
||||||
TriggerGC();
|
TriggerGC(info->num_code_gcs_triggered);
|
||||||
} else if (!current_gc_info_->run_another_gc) {
|
} else if (current_gc_info_->next_gc_sequence_index == 0) {
|
||||||
|
if (inc_gc_count) ++info->num_code_gcs_triggered;
|
||||||
TRACE_CODE_GC(
|
TRACE_CODE_GC(
|
||||||
"Scheduling another GC after the current one (potentially dead: "
|
"Scheduling another GC after the current one (potentially dead: "
|
||||||
"%zu bytes; limit: %zu bytes).\n",
|
"%zu bytes; limit: %zu bytes).\n",
|
||||||
new_potentially_dead_code_size_, dead_code_limit);
|
new_potentially_dead_code_size_, dead_code_limit);
|
||||||
current_gc_info_->run_another_gc = true;
|
current_gc_info_->next_gc_sequence_index = info->num_code_gcs_triggered;
|
||||||
|
DCHECK_NE(0, current_gc_info_->next_gc_sequence_index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -775,10 +799,10 @@ void WasmEngine::FreeDeadCodeLocked(const DeadCodeMap& dead_code) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WasmEngine::TriggerGC() {
|
void WasmEngine::TriggerGC(int8_t gc_sequence_index) {
|
||||||
DCHECK_NULL(current_gc_info_);
|
DCHECK_NULL(current_gc_info_);
|
||||||
DCHECK(FLAG_wasm_code_gc);
|
DCHECK(FLAG_wasm_code_gc);
|
||||||
current_gc_info_.reset(new CurrentGCInfo());
|
current_gc_info_.reset(new CurrentGCInfo(gc_sequence_index));
|
||||||
// Add all potentially dead code to this GC, and trigger a GC task in each
|
// Add all potentially dead code to this GC, and trigger a GC task in each
|
||||||
// isolate.
|
// isolate.
|
||||||
for (auto& entry : native_modules_) {
|
for (auto& entry : native_modules_) {
|
||||||
@ -841,9 +865,9 @@ void WasmEngine::PotentiallyFinishCurrentGC() {
|
|||||||
dead_code[code->native_module()].push_back(code);
|
dead_code[code->native_module()].push_back(code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bool run_another_gc = current_gc_info_->run_another_gc;
|
int8_t next_gc_sequence_index = current_gc_info_->next_gc_sequence_index;
|
||||||
current_gc_info_.reset();
|
current_gc_info_.reset();
|
||||||
if (run_another_gc) TriggerGC();
|
if (next_gc_sequence_index != 0) TriggerGC(next_gc_sequence_index);
|
||||||
|
|
||||||
FreeDeadCodeLocked(dead_code);
|
FreeDeadCodeLocked(dead_code);
|
||||||
}
|
}
|
||||||
|
@ -223,7 +223,7 @@ class V8_EXPORT_PRIVATE WasmEngine {
|
|||||||
Handle<Context> context, const char* api_method_name,
|
Handle<Context> context, const char* api_method_name,
|
||||||
std::shared_ptr<CompilationResultResolver> resolver);
|
std::shared_ptr<CompilationResultResolver> resolver);
|
||||||
|
|
||||||
void TriggerGC();
|
void TriggerGC(int8_t gc_sequence_index);
|
||||||
|
|
||||||
// Remove an isolate from the outstanding isolates of the current GC. Returns
|
// Remove an isolate from the outstanding isolates of the current GC. Returns
|
||||||
// true if the isolate was still outstanding, false otherwise. Hold {mutex_}
|
// true if the isolate was still outstanding, false otherwise. Hold {mutex_}
|
||||||
|
Loading…
Reference in New Issue
Block a user