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 <stddef.h> 9 #include <stdint.h> 10 11 #include <vector> 12 13 #include "v8-internal.h" // NOLINT(build/include_directory) 14 #include "v8-local-handle.h" // NOLINT(build/include_directory) 15 16 namespace v8 { 17 18 class Context; 19 class Isolate; 20 21 namespace metrics { 22 23 struct GarbageCollectionPhases { 24 int64_t compact_wall_clock_duration_in_us = -1; 25 int64_t mark_wall_clock_duration_in_us = -1; 26 int64_t sweep_wall_clock_duration_in_us = -1; 27 int64_t weak_wall_clock_duration_in_us = -1; 28 }; 29 30 struct GarbageCollectionSizes { 31 int64_t bytes_before = -1; 32 int64_t bytes_after = -1; 33 int64_t bytes_freed = -1; 34 }; 35 36 struct GarbageCollectionFullCycle { 37 GarbageCollectionPhases total; 38 GarbageCollectionPhases total_cpp; 39 GarbageCollectionPhases main_thread; 40 GarbageCollectionPhases main_thread_cpp; 41 GarbageCollectionPhases main_thread_atomic; 42 GarbageCollectionPhases main_thread_atomic_cpp; 43 GarbageCollectionPhases main_thread_incremental; 44 GarbageCollectionPhases main_thread_incremental_cpp; 45 GarbageCollectionSizes objects; 46 GarbageCollectionSizes objects_cpp; 47 GarbageCollectionSizes memory; 48 GarbageCollectionSizes memory_cpp; 49 double collection_rate_in_percent; 50 double collection_rate_cpp_in_percent; 51 double efficiency_in_bytes_per_us; 52 double efficiency_cpp_in_bytes_per_us; 53 double main_thread_efficiency_in_bytes_per_us; 54 double main_thread_efficiency_cpp_in_bytes_per_us; 55 }; 56 57 struct GarbageCollectionFullMainThreadIncrementalMark { 58 int64_t wall_clock_duration_in_us = -1; 59 int64_t cpp_wall_clock_duration_in_us = -1; 60 }; 61 62 struct GarbageCollectionFullMainThreadBatchedIncrementalMark { 63 std::vector<GarbageCollectionFullMainThreadIncrementalMark> events; 64 }; 65 66 struct GarbageCollectionFullMainThreadIncrementalSweep { 67 int64_t wall_clock_duration_in_us = -1; 68 int64_t cpp_wall_clock_duration_in_us = -1; 69 }; 70 71 struct GarbageCollectionFullMainThreadBatchedIncrementalSweep { 72 std::vector<GarbageCollectionFullMainThreadIncrementalSweep> events; 73 }; 74 75 struct GarbageCollectionYoungCycle { 76 int64_t total_wall_clock_duration_in_us = -1; 77 int64_t main_thread_wall_clock_duration_in_us = -1; 78 double collection_rate_in_percent; 79 double efficiency_in_bytes_per_us; 80 double main_thread_efficiency_in_bytes_per_us; 81 }; 82 83 struct WasmModuleDecoded { 84 bool async = false; 85 bool streamed = false; 86 bool success = false; 87 size_t module_size_in_bytes = 0; 88 size_t function_count = 0; 89 int64_t wall_clock_duration_in_us = -1; 90 int64_t cpu_duration_in_us = -1; 91 }; 92 93 struct WasmModuleCompiled { 94 bool async = false; 95 bool streamed = false; 96 bool cached = false; 97 bool deserialized = false; 98 bool lazy = false; 99 bool success = false; 100 size_t code_size_in_bytes = 0; 101 size_t liftoff_bailout_count = 0; 102 int64_t wall_clock_duration_in_us = -1; 103 int64_t cpu_duration_in_us = -1; 104 }; 105 106 struct WasmModuleInstantiated { 107 bool async = false; 108 bool success = false; 109 size_t imported_function_count = 0; 110 int64_t wall_clock_duration_in_us = -1; 111 }; 112 113 struct WasmModuleTieredUp { 114 bool lazy = false; 115 size_t code_size_in_bytes = 0; 116 int64_t wall_clock_duration_in_us = -1; 117 int64_t cpu_duration_in_us = -1; 118 }; 119 120 struct WasmModulesPerIsolate { 121 size_t count = 0; 122 }; 123 124 #define V8_MAIN_THREAD_METRICS_EVENTS(V) \ 125 V(GarbageCollectionFullCycle) \ 126 V(GarbageCollectionFullMainThreadIncrementalMark) \ 127 V(GarbageCollectionFullMainThreadBatchedIncrementalMark) \ 128 V(GarbageCollectionFullMainThreadIncrementalSweep) \ 129 V(GarbageCollectionFullMainThreadBatchedIncrementalSweep) \ 130 V(GarbageCollectionYoungCycle) \ 131 V(WasmModuleDecoded) \ 132 V(WasmModuleCompiled) \ 133 V(WasmModuleInstantiated) \ 134 V(WasmModuleTieredUp) 135 136 #define V8_THREAD_SAFE_METRICS_EVENTS(V) V(WasmModulesPerIsolate) 137 138 /** 139 * This class serves as a base class for recording event-based metrics in V8. 140 * There a two kinds of metrics, those which are expected to be thread-safe and 141 * whose implementation is required to fulfill this requirement and those whose 142 * implementation does not have that requirement and only needs to be 143 * executable on the main thread. If such an event is triggered from a 144 * background thread, it will be delayed and executed by the foreground task 145 * runner. 146 * 147 * The thread-safe events are listed in the V8_THREAD_SAFE_METRICS_EVENTS 148 * macro above while the main thread event are listed in 149 * V8_MAIN_THREAD_METRICS_EVENTS above. For the former, a virtual method 150 * AddMainThreadEvent(const E& event, v8::Context::Token token) will be 151 * generated and for the latter AddThreadSafeEvent(const E& event). 152 * 153 * Thread-safe events are not allowed to access the context and therefore do 154 * not carry a context ID with them. These IDs can be generated using 155 * Recorder::GetContextId() and the ID will be valid throughout the lifetime 156 * of the isolate. It is not guaranteed that the ID will still resolve to 157 * a valid context using Recorder::GetContext() at the time the metric is 158 * recorded. In this case, an empty handle will be returned. 159 * 160 * The embedder is expected to call v8::Isolate::SetMetricsRecorder() 161 * providing its implementation and have the virtual methods overwritten 162 * for the events it cares about. 163 */ 164 class V8_EXPORT Recorder { 165 public: 166 // A unique identifier for a context in this Isolate. 167 // It is guaranteed to not be reused throughout the lifetime of the Isolate. 168 class ContextId { 169 public: ContextId()170 ContextId() : id_(kEmptyId) {} 171 IsEmpty()172 bool IsEmpty() const { return id_ == kEmptyId; } Empty()173 static const ContextId Empty() { return ContextId{kEmptyId}; } 174 175 bool operator==(const ContextId& other) const { return id_ == other.id_; } 176 bool operator!=(const ContextId& other) const { return id_ != other.id_; } 177 178 private: 179 friend class ::v8::Context; 180 friend class ::v8::internal::Isolate; 181 ContextId(uintptr_t id)182 explicit ContextId(uintptr_t id) : id_(id) {} 183 184 static constexpr uintptr_t kEmptyId = 0; 185 uintptr_t id_; 186 }; 187 188 virtual ~Recorder() = default; 189 190 #define ADD_MAIN_THREAD_EVENT(E) \ 191 virtual void AddMainThreadEvent(const E& event, ContextId context_id) {} 192 V8_MAIN_THREAD_METRICS_EVENTS(ADD_MAIN_THREAD_EVENT) 193 #undef ADD_MAIN_THREAD_EVENT 194 195 #define ADD_THREAD_SAFE_EVENT(E) \ 196 virtual void AddThreadSafeEvent(const E& event) {} V8_THREAD_SAFE_METRICS_EVENTS(ADD_THREAD_SAFE_EVENT)197 V8_THREAD_SAFE_METRICS_EVENTS(ADD_THREAD_SAFE_EVENT) 198 #undef ADD_THREAD_SAFE_EVENT 199 200 virtual void NotifyIsolateDisposal() {} 201 202 // Return the context with the given id or an empty handle if the context 203 // was already garbage collected. 204 static MaybeLocal<Context> GetContext(Isolate* isolate, ContextId id); 205 // Return the unique id corresponding to the given context. 206 static ContextId GetContextId(Local<Context> context); 207 }; 208 209 /** 210 * Experimental API intended for the LongTasks UKM (crbug.com/1173527). 211 * The Reset() method should be called at the start of a potential 212 * long task. The Get() method returns durations of V8 work that 213 * happened during the task. 214 * 215 * This API is experimental and may be removed/changed in the future. 216 */ 217 struct V8_EXPORT LongTaskStats { 218 /** 219 * Resets durations of V8 work for the new task. 220 */ ResetLongTaskStats221 V8_INLINE static void Reset(Isolate* isolate) { 222 v8::internal::Internals::IncrementLongTasksStatsCounter(isolate); 223 } 224 225 /** 226 * Returns durations of V8 work that happened since the last Reset(). 227 */ 228 static LongTaskStats Get(Isolate* isolate); 229 230 int64_t gc_full_atomic_wall_clock_duration_us = 0; 231 int64_t gc_full_incremental_wall_clock_duration_us = 0; 232 int64_t gc_young_wall_clock_duration_us = 0; 233 }; 234 235 } // namespace metrics 236 } // namespace v8 237 238 #endif // V8_METRICS_H_ 239