Commit 92d493eb authored by Andreas Haas's avatar Andreas Haas Committed by V8 LUCI CQ

[wasm] Add timer for stream finished until compilation finished

With this CL the time is measured from when the streaming decoder is
finished until the time when the compilation of all functions of the
streamed module is finished. If the streaming decoder finishes second,
the time gets recorded negatively. This timer should allow us eventually
to check whether the assumption that Liftoff compilation is faster than
downloading module bytes is correct.

R=clemensb@chromium.org

Bug: v8:12924
Change-Id: I2b7fbdef891d1eda77706ffbd20cf223b91b901c
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3678839
Commit-Queue: Andreas Haas <ahaas@chromium.org>
Reviewed-by: 's avatarClemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/main@{#81915}
parent c3f18ae6
......@@ -101,6 +101,10 @@ namespace internal {
HR(regexp_backtracks, V8.RegExpBacktracks, 1, 100000000, 50) \
/* number of times a cache event is triggered for a wasm module */ \
HR(wasm_cache_count, V8.WasmCacheCount, 0, 100, 101) \
HR(wasm_streaming_until_compilation_finished, \
V8.WasmStreamingUntilCompilationFinishedMilliSeconds, 0, 10000, 50) \
HR(wasm_compilation_until_streaming_finished, \
V8.WasmCompilationUntilStreamFinishedMilliSeconds, 0, 10000, 50) \
SANDBOXED_HISTOGRAM_LIST(HR)
#ifdef V8_ENABLE_SANDBOX
......
......@@ -2329,7 +2329,7 @@ class AsyncCompileJob::CompilationStateCallback
break;
case CompilationEvent::kFinishedBaselineCompilation:
DCHECK_EQ(CompilationEvent::kFinishedExportWrappers, last_event_);
if (job_->DecrementAndCheckFinisherCount()) {
if (job_->DecrementAndCheckFinisherCount(kCompilation)) {
// Install the native module in the cache, or reuse a conflicting one.
// If we get a conflicting module, wait until we are back in the
// main thread to update {job_->native_module_} to avoid a data race.
......@@ -2348,7 +2348,7 @@ class AsyncCompileJob::CompilationStateCallback
case CompilationEvent::kFailedCompilation:
DCHECK(!last_event_.has_value() ||
last_event_ == CompilationEvent::kFinishedExportWrappers);
if (job_->DecrementAndCheckFinisherCount()) {
if (job_->DecrementAndCheckFinisherCount(kCompilation)) {
// Don't update {job_->native_module_} to avoid data races with other
// compilation threads. Use a copy of the shared pointer instead.
std::shared_ptr<NativeModule> native_module = job_->native_module_;
......@@ -2849,7 +2849,7 @@ bool AsyncStreamingProcessor::ProcessCodeSectionHeader(
// Set outstanding_finishers_ to 2, because both the AsyncCompileJob and the
// AsyncStreamingProcessor have to finish.
job_->outstanding_finishers_.store(2);
job_->outstanding_finishers_ = 2;
compilation_unit_builder_ =
InitializeCompilation(job_->isolate(), job_->native_module_.get());
return true;
......@@ -2971,7 +2971,8 @@ void AsyncStreamingProcessor::OnFinishedStream(
job_->native_module_->SetWireBytes(
{std::move(job_->bytes_copy_), job_->wire_bytes_.length()});
}
const bool needs_finish = job_->DecrementAndCheckFinisherCount();
const bool needs_finish =
job_->DecrementAndCheckFinisherCount(AsyncCompileJob::kStreamingDecoder);
DCHECK_IMPLIES(!has_code_section, needs_finish);
if (needs_finish) {
const bool failed = job_->native_module_->compilation_state()->failed();
......
......@@ -15,8 +15,12 @@
#include "include/v8-metrics.h"
#include "src/base/optional.h"
#include "src/base/platform/elapsed-timer.h"
#include "src/base/platform/mutex.h"
#include "src/base/platform/time.h"
#include "src/common/globals.h"
#include "src/execution/isolate.h"
#include "src/logging/counters.h"
#include "src/tasks/cancelable-task.h"
#include "src/wasm/compilation-environment.h"
#include "src/wasm/wasm-features.h"
......@@ -163,12 +167,40 @@ class AsyncCompileJob {
friend class AsyncStreamingProcessor;
enum FinishingComponent { kStreamingDecoder, kCompilation };
// Decrements the number of outstanding finishers. The last caller of this
// function should finish the asynchronous compilation, see the comment on
// {outstanding_finishers_}.
V8_WARN_UNUSED_RESULT bool DecrementAndCheckFinisherCount() {
DCHECK_LT(0, outstanding_finishers_.load());
return outstanding_finishers_.fetch_sub(1) == 1;
V8_WARN_UNUSED_RESULT bool DecrementAndCheckFinisherCount(
FinishingComponent component) {
base::MutexGuard guard(&check_finisher_mutex_);
DCHECK_LT(0, outstanding_finishers_);
if (outstanding_finishers_-- == 2) {
// The first component finished, we just start a timer for a histogram.
streaming_until_finished_timer_.Start();
return false;
}
// The timer has only been started above in the case of streaming
// compilation.
if (streaming_until_finished_timer_.IsStarted()) {
// We measure the time delta from when the StreamingDecoder finishes until
// when module compilation finishes. Depending on whether streaming or
// compilation finishes first we add the delta to the according histogram.
int elapsed = static_cast<int>(
streaming_until_finished_timer_.Elapsed().InMilliseconds());
if (component == kStreamingDecoder) {
isolate_->counters()
->wasm_compilation_until_streaming_finished()
->AddSample(elapsed);
} else {
isolate_->counters()
->wasm_streaming_until_compilation_finished()
->AddSample(elapsed);
}
}
DCHECK_EQ(0, outstanding_finishers_);
return true;
}
void CreateNativeModule(std::shared_ptr<const WasmModule> module,
......@@ -248,7 +280,9 @@ class AsyncCompileJob {
// For async compilation the AsyncCompileJob is the only finisher. For
// streaming compilation also the AsyncStreamingProcessor has to finish before
// compilation can be finished.
std::atomic<int32_t> outstanding_finishers_{1};
int32_t outstanding_finishers_ = 1;
base::ElapsedTimer streaming_until_finished_timer_;
base::Mutex check_finisher_mutex_;
// A reference to a pending foreground task, or {nullptr} if none is pending.
CompileTask* pending_foreground_task_ = nullptr;
......
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