| // Copyright 2020 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef V8_METRICS_H_ |
| #define V8_METRICS_H_ |
| |
| #include "v8.h" // NOLINT(build/include_directory) |
| |
| namespace v8 { |
| namespace metrics { |
| |
| // TODO(sartang@microsoft.com): Remove wall_clock_time_in_us. |
| struct WasmModuleDecoded { |
| bool async = false; |
| bool streamed = false; |
| bool success = false; |
| size_t module_size_in_bytes = 0; |
| size_t function_count = 0; |
| int64_t wall_clock_time_in_us = -1; |
| int64_t wall_clock_duration_in_us = -1; |
| }; |
| |
| struct WasmModuleCompiled { |
| bool async = false; |
| bool streamed = false; |
| bool cached = false; |
| bool deserialized = false; |
| bool lazy = false; |
| bool success = false; |
| size_t code_size_in_bytes = 0; |
| size_t liftoff_bailout_count = 0; |
| int64_t wall_clock_time_in_us = -1; |
| int64_t wall_clock_duration_in_us = -1; |
| }; |
| |
| struct WasmModuleInstantiated { |
| bool async = false; |
| bool success = false; |
| size_t imported_function_count = 0; |
| int64_t wall_clock_time_in_us = -1; |
| int64_t wall_clock_duration_in_us = -1; |
| }; |
| |
| struct WasmModuleTieredUp { |
| bool lazy = false; |
| size_t code_size_in_bytes = 0; |
| int64_t wall_clock_time_in_us = -1; |
| int64_t wall_clock_duration_in_us = -1; |
| }; |
| |
| struct WasmModulesPerIsolate { |
| size_t count = 0; |
| }; |
| |
| #define V8_MAIN_THREAD_METRICS_EVENTS(V) \ |
| V(WasmModuleDecoded) \ |
| V(WasmModuleCompiled) \ |
| V(WasmModuleInstantiated) \ |
| V(WasmModuleTieredUp) |
| |
| #define V8_THREAD_SAFE_METRICS_EVENTS(V) V(WasmModulesPerIsolate) |
| |
| /** |
| * This class serves as a base class for recording event-based metrics in V8. |
| * There a two kinds of metrics, those which are expected to be thread-safe and |
| * whose implementation is required to fulfill this requirement and those whose |
| * implementation does not have that requirement and only needs to be |
| * executable on the main thread. If such an event is triggered from a |
| * background thread, it will be delayed and executed by the foreground task |
| * runner. |
| * |
| * The thread-safe events are listed in the V8_THREAD_SAFE_METRICS_EVENTS |
| * macro above while the main thread event are listed in |
| * V8_MAIN_THREAD_METRICS_EVENTS above. For the former, a virtual method |
| * AddMainThreadEvent(const E& event, v8::Context::Token token) will be |
| * generated and for the latter AddThreadSafeEvent(const E& event). |
| * |
| * Thread-safe events are not allowed to access the context and therefore do |
| * not carry a context ID with them. These IDs can be generated using |
| * Recorder::GetContextId() and the ID will be valid throughout the lifetime |
| * of the isolate. It is not guaranteed that the ID will still resolve to |
| * a valid context using Recorder::GetContext() at the time the metric is |
| * recorded. In this case, an empty handle will be returned. |
| * |
| * The embedder is expected to call v8::Isolate::SetMetricsRecorder() |
| * providing its implementation and have the virtual methods overwritten |
| * for the events it cares about. |
| */ |
| class V8_EXPORT Recorder { |
| public: |
| // A unique identifier for a context in this Isolate. |
| // It is guaranteed to not be reused throughout the lifetime of the Isolate. |
| class ContextId { |
| public: |
| ContextId() : id_(kEmptyId) {} |
| |
| bool IsEmpty() const { return id_ == kEmptyId; } |
| static const ContextId Empty() { return ContextId{kEmptyId}; } |
| |
| bool operator==(const ContextId& other) const { return id_ == other.id_; } |
| bool operator!=(const ContextId& other) const { return id_ != other.id_; } |
| |
| private: |
| friend class ::v8::Context; |
| friend class ::v8::internal::Isolate; |
| |
| explicit ContextId(uintptr_t id) : id_(id) {} |
| |
| static constexpr uintptr_t kEmptyId = 0; |
| uintptr_t id_; |
| }; |
| |
| virtual ~Recorder() = default; |
| |
| #define ADD_MAIN_THREAD_EVENT(E) \ |
| virtual void AddMainThreadEvent(const E& event, ContextId context_id) {} |
| V8_MAIN_THREAD_METRICS_EVENTS(ADD_MAIN_THREAD_EVENT) |
| #undef ADD_MAIN_THREAD_EVENT |
| |
| #define ADD_THREAD_SAFE_EVENT(E) \ |
| virtual void AddThreadSafeEvent(const E& event) {} |
| V8_THREAD_SAFE_METRICS_EVENTS(ADD_THREAD_SAFE_EVENT) |
| #undef ADD_THREAD_SAFE_EVENT |
| |
| virtual void NotifyIsolateDisposal() {} |
| |
| // Return the context with the given id or an empty handle if the context |
| // was already garbage collected. |
| static MaybeLocal<Context> GetContext(Isolate* isolate, ContextId id); |
| // Return the unique id corresponding to the given context. |
| static ContextId GetContextId(Local<Context> context); |
| }; |
| |
| } // namespace metrics |
| } // namespace v8 |
| |
| #endif // V8_METRICS_H_ |