Commit 4c153339 authored by Emanuel Ziegler's avatar Emanuel Ziegler Committed by Commit Bot

[ukm][wasm] Add event WasmModuleDecoded

Add an event for recording metrics related to decoding Wasm modules.

R=clemensb@chromium.org

Bug: chromium:1092417
Change-Id: Id60560d8eb8c14edb5b863857b18c1c82f48e7e7
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2351672
Commit-Queue: Emanuel Ziegler <ecmziegler@chromium.org>
Reviewed-by: 's avatarClemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#69425}
parent 5488d2db
......@@ -1550,10 +1550,12 @@ AsyncCompileJob::AsyncCompileJob(
native_context_ =
isolate->global_handles()->Create(context->native_context());
DCHECK(native_context_->IsNativeContext());
context_id_ = isolate->GetOrRegisterRecorderContextId(native_context_);
}
void AsyncCompileJob::Start() {
DoAsync<DecodeModule>(isolate_->counters()); // --
DoAsync<DecodeModule>(isolate_->counters(),
isolate_->metrics_recorder()); // --
}
void AsyncCompileJob::Abort() {
......@@ -1959,7 +1961,9 @@ void AsyncCompileJob::NextStep(Args&&... args) {
//==========================================================================
class AsyncCompileJob::DecodeModule : public AsyncCompileJob::CompileStep {
public:
explicit DecodeModule(Counters* counters) : counters_(counters) {}
explicit DecodeModule(Counters* counters,
std::shared_ptr<metrics::Recorder> metrics_recorder)
: counters_(counters), metrics_recorder_(std::move(metrics_recorder)) {}
void RunInBackground(AsyncCompileJob* job) override {
ModuleResult result;
......@@ -1971,10 +1975,10 @@ class AsyncCompileJob::DecodeModule : public AsyncCompileJob::CompileStep {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm.detailed"),
"wasm.DecodeModule");
auto enabled_features = job->enabled_features_;
result = DecodeWasmModule(enabled_features, job->wire_bytes_.start(),
job->wire_bytes_.end(), false, kWasmOrigin,
counters_,
job->isolate()->wasm_engine()->allocator());
result = DecodeWasmModule(
enabled_features, job->wire_bytes_.start(), job->wire_bytes_.end(),
false, kWasmOrigin, counters_, metrics_recorder_, job->context_id(),
DecodingMethod::kAsync, job->isolate()->wasm_engine()->allocator());
// Validate lazy functions here if requested.
if (!FLAG_wasm_lazy_validation && result.ok()) {
......@@ -2026,6 +2030,7 @@ class AsyncCompileJob::DecodeModule : public AsyncCompileJob::CompileStep {
private:
Counters* const counters_;
std::shared_ptr<metrics::Recorder> metrics_recorder_;
};
//==========================================================================
......@@ -2216,8 +2221,9 @@ void AsyncStreamingProcessor::FinishAsyncCompileJobWithError(
bool AsyncStreamingProcessor::ProcessModuleHeader(Vector<const uint8_t> bytes,
uint32_t offset) {
TRACE_STREAMING("Process module header...\n");
decoder_.StartDecoding(job_->isolate()->counters(),
job_->isolate()->wasm_engine()->allocator());
decoder_.StartDecoding(
job_->isolate()->counters(), job_->isolate()->metrics_recorder(),
job_->context_id(), job_->isolate()->wasm_engine()->allocator());
decoder_.DecodeModuleHeader(bytes, offset);
if (!decoder_.ok()) {
FinishAsyncCompileJobWithError(decoder_.FinishDecoding(false).error());
......
......@@ -9,6 +9,7 @@
#include <functional>
#include <memory>
#include "include/v8-metrics.h"
#include "src/base/optional.h"
#include "src/common/globals.h"
#include "src/tasks/cancelable-task.h"
......@@ -126,7 +127,8 @@ class AsyncCompileJob {
Isolate* isolate() const { return isolate_; }
Handle<Context> context() const { return native_context_; }
Handle<NativeContext> context() const { return native_context_; }
v8::metrics::Recorder::ContextId context_id() const { return context_id_; }
private:
class CompileTask;
......@@ -209,7 +211,8 @@ class AsyncCompileJob {
// Reference to the wire bytes (held in {bytes_copy_} or as part of
// {native_module_}).
ModuleWireBytes wire_bytes_;
Handle<Context> native_context_;
Handle<NativeContext> native_context_;
v8::metrics::Recorder::ContextId context_id_;
const std::shared_ptr<CompilationResultResolver> resolver_;
Handle<WasmModuleObject> module_object_;
......
......@@ -9,6 +9,7 @@
#include "src/flags/flags.h"
#include "src/init/v8.h"
#include "src/logging/counters.h"
#include "src/logging/metrics.h"
#include "src/objects/objects-inl.h"
#include "src/utils/ostreams.h"
#include "src/wasm/decoder.h"
......@@ -265,6 +266,27 @@ class WasmSectionIterator {
}
};
class AutoSubmitMetrics : public v8::metrics::WasmModuleDecoded {
public:
AutoSubmitMetrics(std::shared_ptr<metrics::Recorder> recorder,
v8::metrics::Recorder::ContextId context_id)
: recorder_(std::move(recorder)),
context_id_(context_id),
timed_scope_(this,
&v8::metrics::WasmModuleDecoded::wall_clock_time_in_us) {}
~AutoSubmitMetrics() {
timed_scope_.Stop();
recorder_->DelayMainThreadEvent<v8::metrics::WasmModuleDecoded>(
*this, context_id_);
}
private:
std::shared_ptr<metrics::Recorder> recorder_;
v8::metrics::Recorder::ContextId context_id_;
metrics::TimedScope<v8::metrics::WasmModuleDecoded> timed_scope_;
};
} // namespace
// The main logic for decoding the bytes of a module.
......@@ -1189,6 +1211,14 @@ class ModuleDecoderImpl : public Decoder {
if (ok() && CheckMismatchedCounts()) {
CalculateGlobalOffsets(module_.get());
}
if (metrics_) {
metrics_->success = ok() && !intermediate_error_.has_error();
metrics_->module_size_in_bytes = end() - start();
metrics_->function_count = module_->num_declared_functions;
metrics_.reset();
}
ModuleResult result = toResult(std::move(module_));
if (verify_functions && result.ok() && intermediate_error_.has_error()) {
// Copy error message and location.
......@@ -1232,6 +1262,13 @@ class ModuleDecoderImpl : public Decoder {
if (FLAG_dump_wasm_module) DumpModule(orig_bytes);
if (decoder.failed()) {
if (metrics_) {
metrics_->success = false;
metrics_->module_size_in_bytes = orig_bytes.length();
metrics_->function_count = module_->num_declared_functions;
metrics_.reset();
}
return decoder.toResult<std::unique_ptr<WasmModule>>(nullptr);
}
......@@ -1285,6 +1322,32 @@ class ModuleDecoderImpl : public Decoder {
counters_ = counters;
}
void EnableMetricsRecording(
std::shared_ptr<metrics::Recorder> metrics_recorder,
v8::metrics::Recorder::ContextId context_id,
DecodingMethod decoding_method) {
metrics_ = std::make_unique<AutoSubmitMetrics>(std::move(metrics_recorder),
context_id);
switch (decoding_method) {
case DecodingMethod::kSync:
break;
case DecodingMethod::kAsync:
metrics_->async = true;
break;
case DecodingMethod::kSyncStream:
metrics_->streamed = true;
break;
case DecodingMethod::kAsyncStream:
metrics_->async = true;
metrics_->streamed = true;
break;
case DecodingMethod::kDeserialize:
// TODO(ecmziegler): verify if we need to add a deserialized metric flag
// in the next UKM update.
break;
}
}
private:
const WasmFeatures enabled_features_;
std::shared_ptr<WasmModule> module_;
......@@ -1310,6 +1373,7 @@ class ModuleDecoderImpl : public Decoder {
// reporting once the whole type section is parsed.
std::unordered_map<uint32_t, int> deferred_check_type_index_;
ModuleOrigin origin_;
std::unique_ptr<AutoSubmitMetrics> metrics_;
ValueType TypeOf(const WasmInitExpr& expr) {
switch (expr.kind()) {
......@@ -2121,11 +2185,12 @@ class ModuleDecoderImpl : public Decoder {
}
};
ModuleResult DecodeWasmModule(const WasmFeatures& enabled,
const byte* module_start, const byte* module_end,
bool verify_functions, ModuleOrigin origin,
Counters* counters,
AccountingAllocator* allocator) {
ModuleResult DecodeWasmModule(
const WasmFeatures& enabled, const byte* module_start,
const byte* module_end, bool verify_functions, ModuleOrigin origin,
Counters* counters, std::shared_ptr<metrics::Recorder> metrics_recorder,
v8::metrics::Recorder::ContextId context_id, DecodingMethod decoding_method,
AccountingAllocator* allocator) {
size_t size = module_end - module_start;
CHECK_LE(module_start, module_end);
size_t max_size = max_module_size();
......@@ -2140,6 +2205,8 @@ ModuleResult DecodeWasmModule(const WasmFeatures& enabled,
// Signatures are stored in zone memory, which have the same lifetime
// as the {module}.
ModuleDecoderImpl decoder(enabled, module_start, module_end, origin);
decoder.EnableMetricsRecording(std::move(metrics_recorder), context_id,
decoding_method);
return decoder.DecodeModule(counters, allocator, verify_functions);
}
......@@ -2152,11 +2219,14 @@ const std::shared_ptr<WasmModule>& ModuleDecoder::shared_module() const {
return impl_->shared_module();
}
void ModuleDecoder::StartDecoding(Counters* counters,
AccountingAllocator* allocator,
ModuleOrigin origin) {
void ModuleDecoder::StartDecoding(
Counters* counters, std::shared_ptr<metrics::Recorder> metrics_recorder,
v8::metrics::Recorder::ContextId context_id, AccountingAllocator* allocator,
ModuleOrigin origin) {
DCHECK_NULL(impl_);
impl_.reset(new ModuleDecoderImpl(enabled_features_, origin));
impl_->EnableMetricsRecording(std::move(metrics_recorder), context_id,
DecodingMethod::kAsyncStream);
impl_->StartDecoding(counters, allocator);
}
......
......@@ -8,6 +8,7 @@
#include <memory>
#include "src/common/globals.h"
#include "src/logging/metrics.h"
#include "src/wasm/function-body-decoder.h"
#include "src/wasm/wasm-constants.h"
#include "src/wasm/wasm-features.h"
......@@ -125,11 +126,21 @@ class LocalNames {
std::vector<LocalNamesPerFunction> functions_;
};
enum class DecodingMethod {
kSync,
kAsync,
kSyncStream,
kAsyncStream,
kDeserialize
};
// Decodes the bytes of a wasm module between {module_start} and {module_end}.
V8_EXPORT_PRIVATE ModuleResult DecodeWasmModule(
const WasmFeatures& enabled, const byte* module_start,
const byte* module_end, bool verify_functions, ModuleOrigin origin,
Counters* counters, AccountingAllocator* allocator);
Counters* counters, std::shared_ptr<metrics::Recorder> metrics_recorder,
v8::metrics::Recorder::ContextId context_id, DecodingMethod decoding_method,
AccountingAllocator* allocator);
// Exposed for testing. Decodes a single function signature, allocating it
// in the given zone. Returns {nullptr} upon failure.
......@@ -188,7 +199,10 @@ class ModuleDecoder {
explicit ModuleDecoder(const WasmFeatures& enabled);
~ModuleDecoder();
void StartDecoding(Counters* counters, AccountingAllocator* allocator,
void StartDecoding(Counters* counters,
std::shared_ptr<metrics::Recorder> metrics_recorder,
v8::metrics::Recorder::ContextId context_id,
AccountingAllocator* allocator,
ModuleOrigin origin = ModuleOrigin::kWasmOrigin);
void DecodeModuleHeader(Vector<const uint8_t> bytes, uint32_t offset);
......
......@@ -443,9 +443,11 @@ bool WasmEngine::SyncValidate(Isolate* isolate, const WasmFeatures& enabled,
TRACE_EVENT0("v8.wasm", "wasm.SyncValidate");
// TODO(titzer): remove dependency on the isolate.
if (bytes.start() == nullptr || bytes.length() == 0) return false;
ModuleResult result =
DecodeWasmModule(enabled, bytes.start(), bytes.end(), true, kWasmOrigin,
isolate->counters(), allocator());
ModuleResult result = DecodeWasmModule(
enabled, bytes.start(), bytes.end(), true, kWasmOrigin,
isolate->counters(), isolate->metrics_recorder(),
isolate->GetOrRegisterRecorderContextId(isolate->native_context()),
DecodingMethod::kSync, allocator());
return result.ok();
}
......@@ -457,9 +459,11 @@ MaybeHandle<AsmWasmData> WasmEngine::SyncCompileTranslatedAsmJs(
ModuleOrigin origin = language_mode == LanguageMode::kSloppy
? kAsmJsSloppyOrigin
: kAsmJsStrictOrigin;
ModuleResult result =
DecodeWasmModule(WasmFeatures::ForAsmjs(), bytes.start(), bytes.end(),
false, origin, isolate->counters(), allocator());
ModuleResult result = DecodeWasmModule(
WasmFeatures::ForAsmjs(), bytes.start(), bytes.end(), false, origin,
isolate->counters(), isolate->metrics_recorder(),
isolate->GetOrRegisterRecorderContextId(isolate->native_context()),
DecodingMethod::kSync, allocator());
if (result.failed()) {
// This happens once in a while when we have missed some limit check
// in the asm parser. Output an error message to help diagnose, but crash.
......@@ -498,9 +502,11 @@ MaybeHandle<WasmModuleObject> WasmEngine::SyncCompile(
Isolate* isolate, const WasmFeatures& enabled, ErrorThrower* thrower,
const ModuleWireBytes& bytes) {
TRACE_EVENT0("v8.wasm", "wasm.SyncCompile");
ModuleResult result =
DecodeWasmModule(enabled, bytes.start(), bytes.end(), false, kWasmOrigin,
isolate->counters(), allocator());
ModuleResult result = DecodeWasmModule(
enabled, bytes.start(), bytes.end(), false, kWasmOrigin,
isolate->counters(), isolate->metrics_recorder(),
isolate->GetOrRegisterRecorderContextId(isolate->native_context()),
DecodingMethod::kSync, allocator());
if (result.failed()) {
thrower->CompileFailed(result.error());
return {};
......
......@@ -618,7 +618,9 @@ MaybeHandle<WasmModuleObject> DeserializeNativeModule(
WasmFeatures enabled_features = WasmFeatures::FromIsolate(isolate);
ModuleResult decode_result = DecodeWasmModule(
enabled_features, wire_bytes.start(), wire_bytes.end(), false,
i::wasm::kWasmOrigin, isolate->counters(), wasm_engine->allocator());
i::wasm::kWasmOrigin, isolate->counters(), isolate->metrics_recorder(),
isolate->GetOrRegisterRecorderContextId(isolate->native_context()),
DecodingMethod::kDeserialize, wasm_engine->allocator());
if (decode_result.failed()) return {};
std::shared_ptr<WasmModule> module = std::move(decode_result.value());
CHECK_NOT_NULL(module);
......
......@@ -309,10 +309,11 @@ STREAM_TEST(TestAllBytesArriveAOTCompilerFinishesFirst) {
size_t GetFunctionOffset(i::Isolate* isolate, const uint8_t* buffer,
size_t size, size_t index) {
ModuleResult result =
DecodeWasmModule(WasmFeatures::All(), buffer, buffer + size, false,
ModuleOrigin::kWasmOrigin, isolate->counters(),
isolate->wasm_engine()->allocator());
ModuleResult result = DecodeWasmModule(
WasmFeatures::All(), buffer, buffer + size, false,
ModuleOrigin::kWasmOrigin, isolate->counters(),
isolate->metrics_recorder(), v8::metrics::Recorder::ContextId::Empty(),
DecodingMethod::kSyncStream, isolate->wasm_engine()->allocator());
CHECK(result.ok());
const WasmFunction* func = &result.value()->functions[index];
return func->code.offset();
......
......@@ -160,7 +160,8 @@ void GenerateTestCase(Isolate* isolate, ModuleWireBytes wire_bytes,
ModuleResult module_res = DecodeWasmModule(
enabled_features, wire_bytes.start(), wire_bytes.end(), kVerifyFunctions,
ModuleOrigin::kWasmOrigin, isolate->counters(),
isolate->wasm_engine()->allocator());
isolate->metrics_recorder(), v8::metrics::Recorder::ContextId::Empty(),
DecodingMethod::kSync, isolate->wasm_engine()->allocator());
CHECK(module_res.ok());
WasmModule* module = module_res.value().get();
CHECK_NOT_NULL(module);
......
......@@ -206,15 +206,19 @@ class WasmModuleVerifyTest : public TestWithIsolateAndZone {
}
ModuleResult result = DecodeWasmModule(
enabled_features_, temp, temp + total, false, kWasmOrigin,
isolate()->counters(), isolate()->wasm_engine()->allocator());
isolate()->counters(), isolate()->metrics_recorder(),
v8::metrics::Recorder::ContextId::Empty(), DecodingMethod::kSync,
isolate()->wasm_engine()->allocator());
delete[] temp;
return result;
}
ModuleResult DecodeModuleNoHeader(const byte* module_start,
const byte* module_end) {
return DecodeWasmModule(enabled_features_, module_start, module_end, false,
kWasmOrigin, isolate()->counters(),
isolate()->wasm_engine()->allocator());
return DecodeWasmModule(
enabled_features_, module_start, module_end, false, kWasmOrigin,
isolate()->counters(), isolate()->metrics_recorder(),
v8::metrics::Recorder::ContextId::Empty(), DecodingMethod::kSync,
isolate()->wasm_engine()->allocator());
}
};
......
......@@ -60,7 +60,8 @@ TEST_F(WasmCapiTest, Traps) {
ModuleResult result = DecodeWasmModule(
WasmFeatures::All(), wire_bytes()->begin(), wire_bytes()->end(), false,
ModuleOrigin::kWasmOrigin, isolate->counters(),
isolate->wasm_engine()->allocator());
isolate->metrics_recorder(), v8::metrics::Recorder::ContextId::Empty(),
DecodingMethod::kSync, isolate->wasm_engine()->allocator());
ASSERT_TRUE(result.ok());
const WasmFunction* func1 = &result.value()->functions[1];
const WasmFunction* func2 = &result.value()->functions[2];
......
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