[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: Clemens Backes <clemensb@chromium.org> Cr-Commit-Position: refs/heads/master@{#69425}
This commit is contained in:
parent
5488d2dbd8
commit
4c153339e5
@ -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];
|
||||
|
Loading…
Reference in New Issue
Block a user