[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:
Clemens Hammacher 2019-05-17 10:33:10 +02:00 committed by Commit Bot
parent 72200ddef4
commit 429ee454e2
3 changed files with 40 additions and 13 deletions

View File

@ -86,7 +86,10 @@ namespace internal {
HR(wasm_module_freed_code_size_mb, V8.WasmModuleCodeSizeFreed, 0, 1024, 64) \
/* percent of freed code size per module, collected on GC */ \
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) \
/* Timer histograms, not thread safe: HT(name, caption, max, unit) */ \

View File

@ -115,6 +115,11 @@ class WasmGCForegroundTask : public Task {
} // namespace
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
// their scheduled foreground task.
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.
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
// only run one GC at a time). Remember though to trigger another one once
// this one finishes.
bool run_another_gc = false;
// this one finishes. {next_gc_sequence_index} is 0 if no next GC is needed,
// 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 {
@ -175,6 +187,10 @@ struct WasmEngine::NativeModuleInfo {
// Code that is not being executed in any isolate any more, but the ref count
// did not drop to zero yet.
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()
@ -704,6 +720,8 @@ void WasmEngine::ReportLiveCodeForGC(Isolate* isolate,
// a foreground task). In that case, ignore it.
if (current_gc_info_ == nullptr) 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);
PotentiallyFinishCurrentGC();
}
@ -725,8 +743,9 @@ bool WasmEngine::AddPotentiallyDeadCode(WasmCode* code) {
base::MutexGuard guard(&mutex_);
auto it = native_modules_.find(code->native_module());
DCHECK_NE(native_modules_.end(), it);
if (it->second->dead_code.count(code)) return false; // Code is already dead.
auto added = it->second->potentially_dead_code.insert(code);
NativeModuleInfo* info = it->second.get();
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.
new_potentially_dead_code_size_ += code->instructions().size();
if (FLAG_wasm_code_gc) {
@ -736,17 +755,22 @@ bool WasmEngine::AddPotentiallyDeadCode(WasmCode* code) {
? 0
: 1 * MB + code_manager_.committed_code_space() / 10;
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 (inc_gc_count) ++info->num_code_gcs_triggered;
TRACE_CODE_GC(
"Triggering GC (potentially dead: %zu bytes; limit: %zu bytes).\n",
new_potentially_dead_code_size_, dead_code_limit);
TriggerGC();
} else if (!current_gc_info_->run_another_gc) {
TriggerGC(info->num_code_gcs_triggered);
} else if (current_gc_info_->next_gc_sequence_index == 0) {
if (inc_gc_count) ++info->num_code_gcs_triggered;
TRACE_CODE_GC(
"Scheduling another GC after the current one (potentially dead: "
"%zu bytes; limit: %zu bytes).\n",
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(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
// isolate.
for (auto& entry : native_modules_) {
@ -841,9 +865,9 @@ void WasmEngine::PotentiallyFinishCurrentGC() {
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();
if (run_another_gc) TriggerGC();
if (next_gc_sequence_index != 0) TriggerGC(next_gc_sequence_index);
FreeDeadCodeLocked(dead_code);
}

View File

@ -223,7 +223,7 @@ class V8_EXPORT_PRIVATE WasmEngine {
Handle<Context> context, const char* api_method_name,
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
// true if the isolate was still outstanding, false otherwise. Hold {mutex_}