1 // Copyright 2021 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_LOGGING_RUNTIME_CALL_STATS_H_ 6 #define V8_LOGGING_RUNTIME_CALL_STATS_H_ 7 8 #ifdef V8_RUNTIME_CALL_STATS 9 10 #include "src/base/atomic-utils.h" 11 #include "src/base/optional.h" 12 #include "src/base/platform/elapsed-timer.h" 13 #include "src/base/platform/time.h" 14 #include "src/builtins/builtins-definitions.h" 15 #include "src/debug/debug-interface.h" 16 #include "src/execution/thread-id.h" 17 #include "src/init/heap-symbols.h" 18 #include "src/logging/tracing-flags.h" 19 #include "src/runtime/runtime.h" 20 #include "src/tracing/traced-value.h" 21 #include "src/tracing/tracing-category-observer.h" 22 23 #endif // V8_RUNTIME_CALL_STATS 24 25 namespace v8 { 26 namespace internal { 27 28 #ifdef V8_RUNTIME_CALL_STATS 29 30 class RuntimeCallCounter final { 31 public: RuntimeCallCounter()32 RuntimeCallCounter() : RuntimeCallCounter(nullptr) {} RuntimeCallCounter(const char * name)33 explicit RuntimeCallCounter(const char* name) 34 : name_(name), count_(0), time_(0) {} 35 V8_NOINLINE void Reset(); 36 V8_NOINLINE void Dump(v8::tracing::TracedValue* value); 37 void Add(RuntimeCallCounter* other); 38 name()39 const char* name() const { return name_; } count()40 int64_t count() const { return count_; } time()41 base::TimeDelta time() const { 42 return base::TimeDelta::FromMicroseconds(time_); 43 } Increment()44 void Increment() { count_++; } Add(base::TimeDelta delta)45 void Add(base::TimeDelta delta) { time_ += delta.InMicroseconds(); } 46 47 private: 48 friend class RuntimeCallStats; 49 50 const char* name_; 51 int64_t count_; 52 // Stored as int64_t so that its initialization can be deferred. 53 int64_t time_; 54 }; 55 56 // RuntimeCallTimer is used to keep track of the stack of currently active 57 // timers used for properly measuring the own time of a RuntimeCallCounter. 58 class RuntimeCallTimer final { 59 public: counter()60 RuntimeCallCounter* counter() { return counter_; } set_counter(RuntimeCallCounter * counter)61 void set_counter(RuntimeCallCounter* counter) { counter_ = counter; } parent()62 RuntimeCallTimer* parent() const { return parent_.Value(); } set_parent(RuntimeCallTimer * timer)63 void set_parent(RuntimeCallTimer* timer) { parent_.SetValue(timer); } name()64 const char* name() const { return counter_->name(); } 65 IsStarted()66 inline bool IsStarted() const { return start_ticks_ != base::TimeTicks(); } 67 Start(RuntimeCallCounter * counter,RuntimeCallTimer * parent)68 inline void Start(RuntimeCallCounter* counter, RuntimeCallTimer* parent) { 69 DCHECK(!IsStarted()); 70 counter_ = counter; 71 parent_.SetValue(parent); 72 if (TracingFlags::runtime_stats.load(std::memory_order_relaxed) == 73 v8::tracing::TracingCategoryObserver::ENABLED_BY_SAMPLING) { 74 return; 75 } 76 base::TimeTicks now = RuntimeCallTimer::Now(); 77 if (parent) parent->Pause(now); 78 Resume(now); 79 DCHECK(IsStarted()); 80 } 81 82 void Snapshot(); 83 Stop()84 inline RuntimeCallTimer* Stop() { 85 if (!IsStarted()) return parent(); 86 base::TimeTicks now = RuntimeCallTimer::Now(); 87 Pause(now); 88 counter_->Increment(); 89 CommitTimeToCounter(); 90 91 RuntimeCallTimer* parent_timer = parent(); 92 if (parent_timer) { 93 parent_timer->Resume(now); 94 } 95 return parent_timer; 96 } 97 98 // Make the time source configurable for testing purposes. 99 V8_EXPORT_PRIVATE static base::TimeTicks (*Now)(); 100 101 // Helper to switch over to CPU time. 102 static base::TimeTicks NowCPUTime(); 103 104 private: Pause(base::TimeTicks now)105 inline void Pause(base::TimeTicks now) { 106 DCHECK(IsStarted()); 107 elapsed_ += (now - start_ticks_); 108 start_ticks_ = base::TimeTicks(); 109 } 110 Resume(base::TimeTicks now)111 inline void Resume(base::TimeTicks now) { 112 DCHECK(!IsStarted()); 113 start_ticks_ = now; 114 } 115 CommitTimeToCounter()116 inline void CommitTimeToCounter() { 117 counter_->Add(elapsed_); 118 elapsed_ = base::TimeDelta(); 119 } 120 121 RuntimeCallCounter* counter_ = nullptr; 122 base::AtomicValue<RuntimeCallTimer*> parent_; 123 base::TimeTicks start_ticks_; 124 base::TimeDelta elapsed_; 125 }; 126 127 #define FOR_EACH_GC_COUNTER(V) \ 128 TRACER_SCOPES(V) \ 129 TRACER_BACKGROUND_SCOPES(V) 130 131 #define FOR_EACH_API_COUNTER(V) \ 132 V(AccessorPair_New) \ 133 V(ArrayBuffer_Cast) \ 134 V(ArrayBuffer_Detach) \ 135 V(ArrayBuffer_New) \ 136 V(ArrayBuffer_NewBackingStore) \ 137 V(ArrayBuffer_BackingStore_Reallocate) \ 138 V(Array_CloneElementAt) \ 139 V(Array_New) \ 140 V(BigInt64Array_New) \ 141 V(BigInt_NewFromWords) \ 142 V(BigIntObject_BigIntValue) \ 143 V(BigIntObject_New) \ 144 V(BigUint64Array_New) \ 145 V(BooleanObject_BooleanValue) \ 146 V(BooleanObject_New) \ 147 V(Context_New) \ 148 V(Context_NewRemoteContext) \ 149 V(DataView_New) \ 150 V(Date_New) \ 151 V(Date_NumberValue) \ 152 V(Debug_Call) \ 153 V(debug_GetPrivateMembers) \ 154 V(Error_New) \ 155 V(External_New) \ 156 V(Float32Array_New) \ 157 V(Float64Array_New) \ 158 V(Function_Call) \ 159 V(Function_New) \ 160 V(Function_FunctionProtoToString) \ 161 V(Function_NewInstance) \ 162 V(FunctionTemplate_GetFunction) \ 163 V(FunctionTemplate_New) \ 164 V(FunctionTemplate_NewRemoteInstance) \ 165 V(FunctionTemplate_NewWithCache) \ 166 V(FunctionTemplate_NewWithFastHandler) \ 167 V(Int16Array_New) \ 168 V(Int32Array_New) \ 169 V(Int8Array_New) \ 170 V(Isolate_DateTimeConfigurationChangeNotification) \ 171 V(Isolate_LocaleConfigurationChangeNotification) \ 172 V(JSON_Parse) \ 173 V(JSON_Stringify) \ 174 V(Map_AsArray) \ 175 V(Map_Clear) \ 176 V(Map_Delete) \ 177 V(Map_Get) \ 178 V(Map_Has) \ 179 V(Map_New) \ 180 V(Map_Set) \ 181 V(Message_GetEndColumn) \ 182 V(Message_GetLineNumber) \ 183 V(Message_GetSourceLine) \ 184 V(Message_GetStartColumn) \ 185 V(Module_Evaluate) \ 186 V(Module_InstantiateModule) \ 187 V(Module_SetSyntheticModuleExport) \ 188 V(NumberObject_New) \ 189 V(NumberObject_NumberValue) \ 190 V(Object_CallAsConstructor) \ 191 V(Object_CallAsFunction) \ 192 V(Object_CreateDataProperty) \ 193 V(Object_DefineOwnProperty) \ 194 V(Object_DefineProperty) \ 195 V(Object_Delete) \ 196 V(Object_DeleteProperty) \ 197 V(Object_ForceSet) \ 198 V(Object_Get) \ 199 V(Object_GetOwnPropertyDescriptor) \ 200 V(Object_GetOwnPropertyNames) \ 201 V(Object_GetPropertyAttributes) \ 202 V(Object_GetPropertyNames) \ 203 V(Object_GetRealNamedProperty) \ 204 V(Object_GetRealNamedPropertyAttributes) \ 205 V(Object_GetRealNamedPropertyAttributesInPrototypeChain) \ 206 V(Object_GetRealNamedPropertyInPrototypeChain) \ 207 V(Object_Has) \ 208 V(Object_HasOwnProperty) \ 209 V(Object_HasRealIndexedProperty) \ 210 V(Object_HasRealNamedCallbackProperty) \ 211 V(Object_HasRealNamedProperty) \ 212 V(Object_IsCodeLike) \ 213 V(Object_New) \ 214 V(Object_ObjectProtoToString) \ 215 V(Object_Set) \ 216 V(Object_SetAccessor) \ 217 V(Object_SetIntegrityLevel) \ 218 V(Object_SetPrivate) \ 219 V(Object_SetPrototype) \ 220 V(ObjectTemplate_New) \ 221 V(ObjectTemplate_NewInstance) \ 222 V(Object_ToArrayIndex) \ 223 V(Object_ToBigInt) \ 224 V(Object_ToDetailString) \ 225 V(Object_ToInt32) \ 226 V(Object_ToInteger) \ 227 V(Object_ToNumber) \ 228 V(Object_ToObject) \ 229 V(Object_ToString) \ 230 V(Object_ToUint32) \ 231 V(Persistent_New) \ 232 V(Private_New) \ 233 V(Promise_Catch) \ 234 V(Promise_Chain) \ 235 V(Promise_HasRejectHandler) \ 236 V(Promise_Resolver_New) \ 237 V(Promise_Resolver_Reject) \ 238 V(Promise_Resolver_Resolve) \ 239 V(Promise_Result) \ 240 V(Promise_Status) \ 241 V(Promise_Then) \ 242 V(Proxy_New) \ 243 V(RangeError_New) \ 244 V(ReferenceError_New) \ 245 V(RegExp_Exec) \ 246 V(RegExp_New) \ 247 V(ScriptCompiler_Compile) \ 248 V(ScriptCompiler_CompileFunctionInContext) \ 249 V(ScriptCompiler_CompileUnbound) \ 250 V(Script_Run) \ 251 V(Set_Add) \ 252 V(Set_AsArray) \ 253 V(Set_Clear) \ 254 V(Set_Delete) \ 255 V(Set_Has) \ 256 V(Set_New) \ 257 V(SharedArrayBuffer_New) \ 258 V(SharedArrayBuffer_NewBackingStore) \ 259 V(String_Concat) \ 260 V(String_NewExternalOneByte) \ 261 V(String_NewExternalTwoByte) \ 262 V(String_NewFromOneByte) \ 263 V(String_NewFromTwoByte) \ 264 V(String_NewFromUtf8) \ 265 V(String_NewFromUtf8Literal) \ 266 V(StringObject_New) \ 267 V(StringObject_StringValue) \ 268 V(String_Write) \ 269 V(String_WriteUtf8) \ 270 V(Symbol_New) \ 271 V(SymbolObject_New) \ 272 V(SymbolObject_SymbolValue) \ 273 V(SyntaxError_New) \ 274 V(TracedGlobal_New) \ 275 V(TryCatch_StackTrace) \ 276 V(TypeError_New) \ 277 V(Uint16Array_New) \ 278 V(Uint32Array_New) \ 279 V(Uint8Array_New) \ 280 V(Uint8ClampedArray_New) \ 281 V(UnboundScript_GetId) \ 282 V(UnboundScript_GetLineNumber) \ 283 V(UnboundScript_GetName) \ 284 V(UnboundScript_GetSourceMappingURL) \ 285 V(UnboundScript_GetSourceURL) \ 286 V(ValueDeserializer_ReadHeader) \ 287 V(ValueDeserializer_ReadValue) \ 288 V(ValueSerializer_WriteValue) \ 289 V(Value_Equals) \ 290 V(Value_InstanceOf) \ 291 V(Value_Int32Value) \ 292 V(Value_IntegerValue) \ 293 V(Value_NumberValue) \ 294 V(Value_TypeOf) \ 295 V(Value_Uint32Value) \ 296 V(WasmCompileError_New) \ 297 V(WasmLinkError_New) \ 298 V(WasmRuntimeError_New) \ 299 V(WeakMap_Delete) \ 300 V(WeakMap_Get) \ 301 V(WeakMap_New) \ 302 V(WeakMap_Set) 303 304 #define ADD_THREAD_SPECIFIC_COUNTER(V, Prefix, Suffix) \ 305 V(Prefix##Suffix) \ 306 V(Prefix##Background##Suffix) 307 308 #define FOR_EACH_THREAD_SPECIFIC_COUNTER(V) \ 309 ADD_THREAD_SPECIFIC_COUNTER(V, Compile, Analyse) \ 310 ADD_THREAD_SPECIFIC_COUNTER(V, Compile, Eval) \ 311 ADD_THREAD_SPECIFIC_COUNTER(V, Compile, Function) \ 312 ADD_THREAD_SPECIFIC_COUNTER(V, Compile, Ignition) \ 313 ADD_THREAD_SPECIFIC_COUNTER(V, Compile, IgnitionFinalization) \ 314 ADD_THREAD_SPECIFIC_COUNTER(V, Compile, RewriteReturnResult) \ 315 ADD_THREAD_SPECIFIC_COUNTER(V, Compile, ScopeAnalysis) \ 316 ADD_THREAD_SPECIFIC_COUNTER(V, Compile, Script) \ 317 \ 318 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, AllocateFPRegisters) \ 319 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, AllocateGeneralRegisters) \ 320 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, AssembleCode) \ 321 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, AssignSpillSlots) \ 322 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, BuildLiveRangeBundles) \ 323 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, BuildLiveRanges) \ 324 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, BytecodeGraphBuilder) \ 325 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, CommitAssignment) \ 326 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, ConnectRanges) \ 327 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, ControlFlowOptimization) \ 328 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, CSAEarlyOptimization) \ 329 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, CSAOptimization) \ 330 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, DecideSpillingMode) \ 331 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, DecompressionOptimization) \ 332 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, EarlyGraphTrimming) \ 333 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, EarlyOptimization) \ 334 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, EffectLinearization) \ 335 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, EscapeAnalysis) \ 336 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, FinalizeCode) \ 337 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, FrameElision) \ 338 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, GenericLowering) \ 339 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, Inlining) \ 340 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, JSWasmInlining) \ 341 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, JumpThreading) \ 342 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, MidTierPopulateReferenceMaps) \ 343 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, MidTierRegisterAllocator) \ 344 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, MidTierRegisterOutputDefinition) \ 345 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, MidTierSpillSlotAllocator) \ 346 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, LateOptimization) \ 347 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, LoadElimination) \ 348 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, LocateSpillSlots) \ 349 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, LoopExitElimination) \ 350 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, LoopPeeling) \ 351 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, MachineOperatorOptimization) \ 352 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, MeetRegisterConstraints) \ 353 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, MemoryOptimization) \ 354 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, OptimizeMoves) \ 355 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, PopulatePointerMaps) \ 356 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, PrintGraph) \ 357 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, ResolveControlFlow) \ 358 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, ResolvePhis) \ 359 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, \ 360 ScheduledEffectControlLinearization) \ 361 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, ScheduledMachineLowering) \ 362 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, Scheduling) \ 363 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, SelectInstructions) \ 364 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, SimplifiedLowering) \ 365 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, StoreStoreElimination) \ 366 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, TraceScheduleAndVerify) \ 367 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, TypeAssertions) \ 368 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, TypedLowering) \ 369 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, Typer) \ 370 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, Untyper) \ 371 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, VerifyGraph) \ 372 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, WasmBaseOptimization) \ 373 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, WasmInlining) \ 374 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, WasmLoopUnrolling) \ 375 ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, WasmOptimization) \ 376 \ 377 ADD_THREAD_SPECIFIC_COUNTER(V, Parse, ArrowFunctionLiteral) \ 378 ADD_THREAD_SPECIFIC_COUNTER(V, Parse, FunctionLiteral) \ 379 ADD_THREAD_SPECIFIC_COUNTER(V, Parse, Program) \ 380 ADD_THREAD_SPECIFIC_COUNTER(V, PreParse, ArrowFunctionLiteral) \ 381 ADD_THREAD_SPECIFIC_COUNTER(V, PreParse, WithVariableResolution) 382 383 #define FOR_EACH_MANUAL_COUNTER(V) \ 384 V(AccessorGetterCallback) \ 385 V(AccessorSetterCallback) \ 386 V(ArrayLengthGetter) \ 387 V(ArrayLengthSetter) \ 388 V(BoundFunctionLengthGetter) \ 389 V(BoundFunctionNameGetter) \ 390 V(CodeGenerationFromStringsCallbacks) \ 391 V(CompileBackgroundCompileTask) \ 392 V(CompileBaseline) \ 393 V(CompileBaselinePreVisit) \ 394 V(CompileBaselineVisit) \ 395 V(CompileCollectSourcePositions) \ 396 V(CompileDeserialize) \ 397 V(CompileEnqueueOnDispatcher) \ 398 V(CompileFinalizeBackgroundCompileTask) \ 399 V(CompileFinishNowOnDispatcher) \ 400 V(CompileGetFromOptimizedCodeMap) \ 401 V(CompilePublishBackgroundFinalization) \ 402 V(CompileSerialize) \ 403 V(CompileWaitForDispatcher) \ 404 V(ConfigureInstance) \ 405 V(CreateApiFunction) \ 406 V(Debugger) \ 407 V(DebuggerCallback) \ 408 V(DeoptimizeCode) \ 409 V(DeserializeContext) \ 410 V(DeserializeIsolate) \ 411 V(FinalizationRegistryCleanupFromTask) \ 412 V(FunctionCallback) \ 413 V(FunctionLengthGetter) \ 414 V(FunctionPrototypeGetter) \ 415 V(FunctionPrototypeSetter) \ 416 V(GCEpilogueCallback) \ 417 V(GCPrologueCallback) \ 418 V(GC_Custom_AllAvailableGarbage) \ 419 V(GC_Custom_IncrementalMarkingObserver) \ 420 V(GC_Custom_SlowAllocateRaw) \ 421 V(Genesis) \ 422 V(GetCompatibleReceiver) \ 423 V(GetMoreDataCallback) \ 424 V(IndexedDefinerCallback) \ 425 V(IndexedDeleterCallback) \ 426 V(IndexedDescriptorCallback) \ 427 V(IndexedEnumeratorCallback) \ 428 V(IndexedGetterCallback) \ 429 V(IndexedQueryCallback) \ 430 V(IndexedSetterCallback) \ 431 V(InstantiateFunction) \ 432 V(InstantiateObject) \ 433 V(Invoke) \ 434 V(InvokeApiFunction) \ 435 V(InvokeApiInterruptCallbacks) \ 436 V(IsCompatibleReceiver) \ 437 V(IsCompatibleReceiverMap) \ 438 V(IsTemplateFor) \ 439 V(JS_Execution) \ 440 V(Map_SetPrototype) \ 441 V(Map_TransitionToAccessorProperty) \ 442 V(Map_TransitionToDataProperty) \ 443 V(MessageListenerCallback) \ 444 V(NamedDefinerCallback) \ 445 V(NamedDeleterCallback) \ 446 V(NamedDescriptorCallback) \ 447 V(NamedEnumeratorCallback) \ 448 V(NamedGetterCallback) \ 449 V(NamedQueryCallback) \ 450 V(NamedSetterCallback) \ 451 V(ObjectVerify) \ 452 V(Object_DeleteProperty) \ 453 V(OptimizeBackgroundDispatcherJob) \ 454 V(OptimizeCode) \ 455 V(OptimizeConcurrentFinalize) \ 456 V(OptimizeConcurrentPrepare) \ 457 V(OptimizeFinalizePipelineJob) \ 458 V(OptimizeHeapBrokerInitialization) \ 459 V(OptimizeNonConcurrent) \ 460 V(OptimizeSerialization) \ 461 V(OptimizeSerializeMetadata) \ 462 V(ParseEval) \ 463 V(ParseFunction) \ 464 V(PropertyCallback) \ 465 V(PrototypeMap_TransitionToAccessorProperty) \ 466 V(PrototypeMap_TransitionToDataProperty) \ 467 V(PrototypeObject_DeleteProperty) \ 468 V(ReconfigureToDataProperty) \ 469 V(StringLengthGetter) \ 470 V(TestCounter1) \ 471 V(TestCounter2) \ 472 V(TestCounter3) \ 473 V(UpdateProtector) \ 474 V(WebSnapshotDeserialize) \ 475 V(WebSnapshotDeserialize_Arrays) \ 476 V(WebSnapshotDeserialize_Contexts) \ 477 V(WebSnapshotDeserialize_Exports) \ 478 V(WebSnapshotDeserialize_Functions) \ 479 V(WebSnapshotDeserialize_Classes) \ 480 V(WebSnapshotDeserialize_Maps) \ 481 V(WebSnapshotDeserialize_Objects) \ 482 V(WebSnapshotDeserialize_Strings) 483 484 #define FOR_EACH_HANDLER_COUNTER(V) \ 485 V(KeyedLoadIC_KeyedLoadSloppyArgumentsStub) \ 486 V(KeyedLoadIC_LoadElementDH) \ 487 V(KeyedLoadIC_LoadIndexedInterceptorStub) \ 488 V(KeyedLoadIC_LoadIndexedStringDH) \ 489 V(KeyedLoadIC_SlowStub) \ 490 V(KeyedStoreIC_ElementsTransitionAndStoreStub) \ 491 V(KeyedStoreIC_KeyedStoreSloppyArgumentsStub) \ 492 V(KeyedStoreIC_SlowStub) \ 493 V(KeyedStoreIC_StoreElementStub) \ 494 V(KeyedStoreIC_StoreFastElementStub) \ 495 V(LoadGlobalIC_LoadScriptContextField) \ 496 V(LoadGlobalIC_SlowStub) \ 497 V(LoadIC_FunctionPrototypeStub) \ 498 V(LoadIC_HandlerCacheHit_Accessor) \ 499 V(LoadIC_LoadAccessorDH) \ 500 V(LoadIC_LoadAccessorFromPrototypeDH) \ 501 V(LoadIC_LoadApiGetterFromPrototypeDH) \ 502 V(LoadIC_LoadCallback) \ 503 V(LoadIC_LoadConstantDH) \ 504 V(LoadIC_LoadConstantFromPrototypeDH) \ 505 V(LoadIC_LoadFieldDH) \ 506 V(LoadIC_LoadFieldFromPrototypeDH) \ 507 V(LoadIC_LoadGlobalDH) \ 508 V(LoadIC_LoadGlobalFromPrototypeDH) \ 509 V(LoadIC_LoadIntegerIndexedExoticDH) \ 510 V(LoadIC_LoadInterceptorDH) \ 511 V(LoadIC_LoadInterceptorFromPrototypeDH) \ 512 V(LoadIC_LoadNativeDataPropertyDH) \ 513 V(LoadIC_LoadNativeDataPropertyFromPrototypeDH) \ 514 V(LoadIC_LoadNonexistentDH) \ 515 V(LoadIC_LoadNonMaskingInterceptorDH) \ 516 V(LoadIC_LoadNormalDH) \ 517 V(LoadIC_LoadNormalFromPrototypeDH) \ 518 V(LoadIC_NonReceiver) \ 519 V(LoadIC_SlowStub) \ 520 V(LoadIC_StringLength) \ 521 V(LoadIC_StringWrapperLength) \ 522 V(StoreGlobalIC_SlowStub) \ 523 V(StoreGlobalIC_StoreScriptContextField) \ 524 V(StoreIC_HandlerCacheHit_Accessor) \ 525 V(StoreIC_NonReceiver) \ 526 V(StoreIC_SlowStub) \ 527 V(StoreIC_StoreAccessorDH) \ 528 V(StoreIC_StoreAccessorOnPrototypeDH) \ 529 V(StoreIC_StoreApiSetterOnPrototypeDH) \ 530 V(StoreIC_StoreFieldDH) \ 531 V(StoreIC_StoreGlobalDH) \ 532 V(StoreIC_StoreGlobalTransitionDH) \ 533 V(StoreIC_StoreInterceptorStub) \ 534 V(StoreIC_StoreNativeDataPropertyDH) \ 535 V(StoreIC_StoreNativeDataPropertyOnPrototypeDH) \ 536 V(StoreIC_StoreNormalDH) \ 537 V(StoreIC_StoreTransitionDH) \ 538 V(StoreInArrayLiteralIC_SlowStub) 539 540 enum RuntimeCallCounterId { 541 #define CALL_RUNTIME_COUNTER(name) kGC_##name, 542 FOR_EACH_GC_COUNTER(CALL_RUNTIME_COUNTER) 543 #undef CALL_RUNTIME_COUNTER 544 #define CALL_RUNTIME_COUNTER(name) k##name, 545 FOR_EACH_MANUAL_COUNTER(CALL_RUNTIME_COUNTER) 546 #undef CALL_RUNTIME_COUNTER 547 #define CALL_RUNTIME_COUNTER(name, nargs, ressize) kRuntime_##name, 548 FOR_EACH_INTRINSIC(CALL_RUNTIME_COUNTER) 549 #undef CALL_RUNTIME_COUNTER 550 #define CALL_BUILTIN_COUNTER(name) kBuiltin_##name, 551 BUILTIN_LIST_C(CALL_BUILTIN_COUNTER) 552 #undef CALL_BUILTIN_COUNTER 553 #define CALL_BUILTIN_COUNTER(name) kAPI_##name, 554 FOR_EACH_API_COUNTER(CALL_BUILTIN_COUNTER) 555 #undef CALL_BUILTIN_COUNTER 556 #define CALL_BUILTIN_COUNTER(name) kHandler_##name, 557 FOR_EACH_HANDLER_COUNTER(CALL_BUILTIN_COUNTER) 558 #undef CALL_BUILTIN_COUNTER 559 #define THREAD_SPECIFIC_COUNTER(name) k##name, 560 FOR_EACH_THREAD_SPECIFIC_COUNTER( 561 THREAD_SPECIFIC_COUNTER) 562 #undef THREAD_SPECIFIC_COUNTER 563 kNumberOfCounters, 564 }; 565 566 class RuntimeCallStats final { 567 public: 568 enum ThreadType { kMainIsolateThread, kWorkerThread }; 569 570 // If kExact is chosen the counter will be use as given. With kThreadSpecific, 571 // if the RuntimeCallStats was created for a worker thread, then the 572 // background specific version of the counter will be used instead. 573 enum CounterMode { kExact, kThreadSpecific }; 574 575 explicit V8_EXPORT_PRIVATE RuntimeCallStats(ThreadType thread_type); 576 577 // Starting measuring the time for a function. This will establish the 578 // connection to the parent counter for properly calculating the own times. 579 V8_EXPORT_PRIVATE void Enter(RuntimeCallTimer* timer, 580 RuntimeCallCounterId counter_id); 581 582 // Leave a scope for a measured runtime function. This will properly add 583 // the time delta to the current_counter and subtract the delta from its 584 // parent. 585 V8_EXPORT_PRIVATE void Leave(RuntimeCallTimer* timer); 586 587 // Set counter id for the innermost measurement. It can be used to refine 588 // event kind when a runtime entry counter is too generic. 589 V8_EXPORT_PRIVATE void CorrectCurrentCounterId( 590 RuntimeCallCounterId counter_id, CounterMode mode = kExact); 591 592 V8_EXPORT_PRIVATE void Reset(); 593 // Add all entries from another stats object. 594 void Add(RuntimeCallStats* other); 595 V8_EXPORT_PRIVATE void Print(std::ostream& os); 596 V8_EXPORT_PRIVATE void Print(); 597 V8_NOINLINE void Dump(v8::tracing::TracedValue* value); 598 thread_id()599 ThreadId thread_id() const { return thread_id_; } current_timer()600 RuntimeCallTimer* current_timer() { return current_timer_.Value(); } current_counter()601 RuntimeCallCounter* current_counter() { return current_counter_.Value(); } InUse()602 bool InUse() { return in_use_; } 603 bool IsCalledOnTheSameThread(); 604 605 V8_EXPORT_PRIVATE bool IsBackgroundThreadSpecificVariant( 606 RuntimeCallCounterId id); 607 V8_EXPORT_PRIVATE bool HasThreadSpecificCounterVariants( 608 RuntimeCallCounterId id); 609 610 // This should only be called for counters with a dual Background variant. If 611 // on the main thread, this just returns the counter. If on a worker thread, 612 // it returns Background variant of the counter. CounterIdForThread(RuntimeCallCounterId id)613 RuntimeCallCounterId CounterIdForThread(RuntimeCallCounterId id) { 614 DCHECK(HasThreadSpecificCounterVariants(id)); 615 // All thread specific counters are laid out with the main thread variant 616 // first followed by the background variant. 617 return thread_type_ == kWorkerThread 618 ? static_cast<RuntimeCallCounterId>(id + 1) 619 : id; 620 } 621 IsCounterAppropriateForThread(RuntimeCallCounterId id)622 bool IsCounterAppropriateForThread(RuntimeCallCounterId id) { 623 // TODO(delphick): We should add background-only counters and ensure that 624 // all counters (not just the thread-specific variants) are only invoked on 625 // the correct thread. 626 if (!HasThreadSpecificCounterVariants(id)) return true; 627 return IsBackgroundThreadSpecificVariant(id) == 628 (thread_type_ == kWorkerThread); 629 } 630 631 static const int kNumberOfCounters = 632 static_cast<int>(RuntimeCallCounterId::kNumberOfCounters); GetCounter(RuntimeCallCounterId counter_id)633 RuntimeCallCounter* GetCounter(RuntimeCallCounterId counter_id) { 634 return &counters_[static_cast<int>(counter_id)]; 635 } GetCounter(int counter_id)636 RuntimeCallCounter* GetCounter(int counter_id) { 637 return &counters_[counter_id]; 638 } 639 640 private: 641 // Top of a stack of active timers. 642 base::AtomicValue<RuntimeCallTimer*> current_timer_; 643 // Active counter object associated with current timer. 644 base::AtomicValue<RuntimeCallCounter*> current_counter_; 645 // Used to track nested tracing scopes. 646 bool in_use_; 647 ThreadType thread_type_; 648 ThreadId thread_id_; 649 RuntimeCallCounter counters_[kNumberOfCounters]; 650 }; 651 652 class WorkerThreadRuntimeCallStats final { 653 public: 654 WorkerThreadRuntimeCallStats(); 655 ~WorkerThreadRuntimeCallStats(); 656 657 // Returns the TLS key associated with this WorkerThreadRuntimeCallStats. 658 base::Thread::LocalStorageKey GetKey(); 659 660 // Returns a new worker thread runtime call stats table managed by this 661 // WorkerThreadRuntimeCallStats. 662 RuntimeCallStats* NewTable(); 663 664 // Adds the counters from the worker thread tables to |main_call_stats|. 665 void AddToMainTable(RuntimeCallStats* main_call_stats); 666 667 private: 668 base::Mutex mutex_; 669 std::vector<std::unique_ptr<RuntimeCallStats>> tables_; 670 base::Optional<base::Thread::LocalStorageKey> tls_key_; 671 // Since this is for creating worker thread runtime-call stats, record the 672 // main thread ID to ensure we never create a worker RCS table for the main 673 // thread. 674 ThreadId isolate_thread_id_; 675 }; 676 677 // Creating a WorkerThreadRuntimeCallStatsScope will provide a thread-local 678 // runtime call stats table, and will dump the table to an immediate trace event 679 // when it is destroyed. 680 class V8_NODISCARD WorkerThreadRuntimeCallStatsScope final { 681 public: 682 explicit WorkerThreadRuntimeCallStatsScope( 683 WorkerThreadRuntimeCallStats* off_thread_stats); 684 ~WorkerThreadRuntimeCallStatsScope(); 685 Get()686 RuntimeCallStats* Get() const { return table_; } 687 688 private: 689 RuntimeCallStats* table_; 690 }; 691 692 #define CHANGE_CURRENT_RUNTIME_COUNTER(runtime_call_stats, counter_id) \ 693 do { \ 694 if (V8_UNLIKELY(TracingFlags::is_runtime_stats_enabled()) && \ 695 runtime_call_stats) { \ 696 runtime_call_stats->CorrectCurrentCounterId(counter_id); \ 697 } \ 698 } while (false) 699 700 #define TRACE_HANDLER_STATS(isolate, counter_name) \ 701 CHANGE_CURRENT_RUNTIME_COUNTER( \ 702 isolate->counters()->runtime_call_stats(), \ 703 RuntimeCallCounterId::kHandler_##counter_name) 704 705 // A RuntimeCallTimerScopes wraps around a RuntimeCallTimer to measure the 706 // the time of C++ scope. 707 class V8_NODISCARD RuntimeCallTimerScope { 708 public: 709 inline RuntimeCallTimerScope(Isolate* isolate, 710 RuntimeCallCounterId counter_id); 711 inline RuntimeCallTimerScope(RuntimeCallStats* stats, 712 RuntimeCallCounterId counter_id, 713 RuntimeCallStats::CounterMode mode = 714 RuntimeCallStats::CounterMode::kExact) { 715 if (V8_LIKELY(!TracingFlags::is_runtime_stats_enabled() || 716 stats == nullptr)) { 717 return; 718 } 719 stats_ = stats; 720 if (mode == RuntimeCallStats::CounterMode::kThreadSpecific) { 721 counter_id = stats->CounterIdForThread(counter_id); 722 } 723 724 DCHECK(stats->IsCounterAppropriateForThread(counter_id)); 725 stats_->Enter(&timer_, counter_id); 726 } 727 ~RuntimeCallTimerScope()728 inline ~RuntimeCallTimerScope() { 729 if (V8_UNLIKELY(stats_ != nullptr)) { 730 stats_->Leave(&timer_); 731 } 732 } 733 734 RuntimeCallTimerScope(const RuntimeCallTimerScope&) = delete; 735 RuntimeCallTimerScope& operator=(const RuntimeCallTimerScope&) = delete; 736 737 private: 738 RuntimeCallStats* stats_ = nullptr; 739 RuntimeCallTimer timer_; 740 }; 741 742 #else // RUNTIME_CALL_STATS 743 744 #define TRACE_HANDLER_STATS(...) 745 #define CHANGE_CURRENT_RUNTIME_COUNTER(...) 746 747 // Create dummy types to limit code changes 748 class WorkerThreadRuntimeCallStats {}; 749 750 class RuntimeCallStats { 751 public: 752 enum ThreadType { kMainIsolateThread, kWorkerThread }; 753 explicit V8_EXPORT_PRIVATE RuntimeCallStats(ThreadType thread_type) {} 754 }; 755 756 class WorkerThreadRuntimeCallStatsScope { 757 public: 758 explicit WorkerThreadRuntimeCallStatsScope( 759 WorkerThreadRuntimeCallStats* off_thread_stats) {} 760 RuntimeCallStats* Get() const { return nullptr; } 761 }; 762 763 #endif // RUNTIME_CALL_STATS 764 765 } // namespace internal 766 } // namespace v8 767 768 #endif // V8_LOGGING_RUNTIME_CALL_STATS_H_ 769