1 // Copyright 2020 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_METRICS_H_ 6 #define V8_METRICS_H_ 7 8 #include "v8.h" // NOLINT(build/include_directory) 9 10 namespace v8 { 11 namespace metrics { 12 13 // TODO(sartang@microsoft.com): Remove wall_clock_time_in_us. 14 struct WasmModuleDecoded { 15 bool async = false; 16 bool streamed = false; 17 bool success = false; 18 size_t module_size_in_bytes = 0; 19 size_t function_count = 0; 20 int64_t wall_clock_time_in_us = -1; 21 int64_t wall_clock_duration_in_us = -1; 22 }; 23 24 struct WasmModuleCompiled { 25 bool async = false; 26 bool streamed = false; 27 bool cached = false; 28 bool deserialized = false; 29 bool lazy = false; 30 bool success = false; 31 size_t code_size_in_bytes = 0; 32 size_t liftoff_bailout_count = 0; 33 int64_t wall_clock_time_in_us = -1; 34 int64_t wall_clock_duration_in_us = -1; 35 }; 36 37 struct WasmModuleInstantiated { 38 bool async = false; 39 bool success = false; 40 size_t imported_function_count = 0; 41 int64_t wall_clock_time_in_us = -1; 42 int64_t wall_clock_duration_in_us = -1; 43 }; 44 45 struct WasmModuleTieredUp { 46 bool lazy = false; 47 size_t code_size_in_bytes = 0; 48 int64_t wall_clock_time_in_us = -1; 49 int64_t wall_clock_duration_in_us = -1; 50 }; 51 52 struct WasmModulesPerIsolate { 53 size_t count = 0; 54 }; 55 56 #define V8_MAIN_THREAD_METRICS_EVENTS(V) \ 57 V(WasmModuleDecoded) \ 58 V(WasmModuleCompiled) \ 59 V(WasmModuleInstantiated) \ 60 V(WasmModuleTieredUp) 61 62 #define V8_THREAD_SAFE_METRICS_EVENTS(V) V(WasmModulesPerIsolate) 63 64 /** 65 * This class serves as a base class for recording event-based metrics in V8. 66 * There a two kinds of metrics, those which are expected to be thread-safe and 67 * whose implementation is required to fulfill this requirement and those whose 68 * implementation does not have that requirement and only needs to be 69 * executable on the main thread. If such an event is triggered from a 70 * background thread, it will be delayed and executed by the foreground task 71 * runner. 72 * 73 * The thread-safe events are listed in the V8_THREAD_SAFE_METRICS_EVENTS 74 * macro above while the main thread event are listed in 75 * V8_MAIN_THREAD_METRICS_EVENTS above. For the former, a virtual method 76 * AddMainThreadEvent(const E& event, v8::Context::Token token) will be 77 * generated and for the latter AddThreadSafeEvent(const E& event). 78 * 79 * Thread-safe events are not allowed to access the context and therefore do 80 * not carry a context ID with them. These IDs can be generated using 81 * Recorder::GetContextId() and the ID will be valid throughout the lifetime 82 * of the isolate. It is not guaranteed that the ID will still resolve to 83 * a valid context using Recorder::GetContext() at the time the metric is 84 * recorded. In this case, an empty handle will be returned. 85 * 86 * The embedder is expected to call v8::Isolate::SetMetricsRecorder() 87 * providing its implementation and have the virtual methods overwritten 88 * for the events it cares about. 89 */ 90 class V8_EXPORT Recorder { 91 public: 92 // A unique identifier for a context in this Isolate. 93 // It is guaranteed to not be reused throughout the lifetime of the Isolate. 94 class ContextId { 95 public: ContextId()96 ContextId() : id_(kEmptyId) {} 97 IsEmpty()98 bool IsEmpty() const { return id_ == kEmptyId; } Empty()99 static const ContextId Empty() { return ContextId{kEmptyId}; } 100 101 bool operator==(const ContextId& other) const { return id_ == other.id_; } 102 bool operator!=(const ContextId& other) const { return id_ != other.id_; } 103 104 private: 105 friend class ::v8::Context; 106 friend class ::v8::internal::Isolate; 107 ContextId(uintptr_t id)108 explicit ContextId(uintptr_t id) : id_(id) {} 109 110 static constexpr uintptr_t kEmptyId = 0; 111 uintptr_t id_; 112 }; 113 114 virtual ~Recorder() = default; 115 116 #define ADD_MAIN_THREAD_EVENT(E) \ 117 virtual void AddMainThreadEvent(const E& event, ContextId context_id) {} 118 V8_MAIN_THREAD_METRICS_EVENTS(ADD_MAIN_THREAD_EVENT) 119 #undef ADD_MAIN_THREAD_EVENT 120 121 #define ADD_THREAD_SAFE_EVENT(E) \ 122 virtual void AddThreadSafeEvent(const E& event) {} V8_THREAD_SAFE_METRICS_EVENTS(ADD_THREAD_SAFE_EVENT)123 V8_THREAD_SAFE_METRICS_EVENTS(ADD_THREAD_SAFE_EVENT) 124 #undef ADD_THREAD_SAFE_EVENT 125 126 virtual void NotifyIsolateDisposal() {} 127 128 // Return the context with the given id or an empty handle if the context 129 // was already garbage collected. 130 static MaybeLocal<Context> GetContext(Isolate* isolate, ContextId id); 131 // Return the unique id corresponding to the given context. 132 static ContextId GetContextId(Local<Context> context); 133 }; 134 135 } // namespace metrics 136 } // namespace v8 137 138 #endif // V8_METRICS_H_ 139