summaryrefslogtreecommitdiff
path: root/chromium/v8/src/logging/runtime-call-stats.h
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/v8/src/logging/runtime-call-stats.h')
-rw-r--r--chromium/v8/src/logging/runtime-call-stats.h763
1 files changed, 763 insertions, 0 deletions
diff --git a/chromium/v8/src/logging/runtime-call-stats.h b/chromium/v8/src/logging/runtime-call-stats.h
new file mode 100644
index 00000000000..7593170d865
--- /dev/null
+++ b/chromium/v8/src/logging/runtime-call-stats.h
@@ -0,0 +1,763 @@
+// Copyright 2021 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_LOGGING_RUNTIME_CALL_STATS_H_
+#define V8_LOGGING_RUNTIME_CALL_STATS_H_
+
+#include "include/v8.h"
+
+#ifdef V8_RUNTIME_CALL_STATS
+
+#include "src/base/atomic-utils.h"
+#include "src/base/optional.h"
+#include "src/base/platform/elapsed-timer.h"
+#include "src/base/platform/time.h"
+#include "src/builtins/builtins-definitions.h"
+#include "src/debug/debug-interface.h"
+#include "src/execution/thread-id.h"
+#include "src/init/heap-symbols.h"
+#include "src/logging/tracing-flags.h"
+#include "src/runtime/runtime.h"
+#include "src/tracing/traced-value.h"
+#include "src/tracing/tracing-category-observer.h"
+
+#endif // V8_RUNTIME_CALL_STATS
+
+namespace v8 {
+namespace internal {
+
+#ifdef V8_RUNTIME_CALL_STATS
+
+#define RCS_SCOPE(...) \
+ v8::internal::RuntimeCallTimerScope rcs_timer_scope(__VA_ARGS__)
+
+class RuntimeCallCounter final {
+ public:
+ RuntimeCallCounter() : RuntimeCallCounter(nullptr) {}
+ explicit RuntimeCallCounter(const char* name)
+ : name_(name), count_(0), time_(0) {}
+ V8_NOINLINE void Reset();
+ V8_NOINLINE void Dump(v8::tracing::TracedValue* value);
+ void Add(RuntimeCallCounter* other);
+
+ const char* name() const { return name_; }
+ int64_t count() const { return count_; }
+ base::TimeDelta time() const {
+ return base::TimeDelta::FromMicroseconds(time_);
+ }
+ void Increment() { count_++; }
+ void Add(base::TimeDelta delta) { time_ += delta.InMicroseconds(); }
+
+ private:
+ friend class RuntimeCallStats;
+
+ const char* name_;
+ int64_t count_;
+ // Stored as int64_t so that its initialization can be deferred.
+ int64_t time_;
+};
+
+// RuntimeCallTimer is used to keep track of the stack of currently active
+// timers used for properly measuring the own time of a RuntimeCallCounter.
+class RuntimeCallTimer final {
+ public:
+ RuntimeCallCounter* counter() { return counter_; }
+ void set_counter(RuntimeCallCounter* counter) { counter_ = counter; }
+ RuntimeCallTimer* parent() const { return parent_.Value(); }
+ void set_parent(RuntimeCallTimer* timer) { parent_.SetValue(timer); }
+ const char* name() const { return counter_->name(); }
+
+ inline bool IsStarted() const { return start_ticks_ != base::TimeTicks(); }
+
+ inline void Start(RuntimeCallCounter* counter, RuntimeCallTimer* parent) {
+ DCHECK(!IsStarted());
+ counter_ = counter;
+ parent_.SetValue(parent);
+ if (TracingFlags::runtime_stats.load(std::memory_order_relaxed) ==
+ v8::tracing::TracingCategoryObserver::ENABLED_BY_SAMPLING) {
+ return;
+ }
+ base::TimeTicks now = RuntimeCallTimer::Now();
+ if (parent) parent->Pause(now);
+ Resume(now);
+ DCHECK(IsStarted());
+ }
+
+ void Snapshot();
+
+ inline RuntimeCallTimer* Stop() {
+ if (!IsStarted()) return parent();
+ base::TimeTicks now = RuntimeCallTimer::Now();
+ Pause(now);
+ counter_->Increment();
+ CommitTimeToCounter();
+
+ RuntimeCallTimer* parent_timer = parent();
+ if (parent_timer) {
+ parent_timer->Resume(now);
+ }
+ return parent_timer;
+ }
+
+ // Make the time source configurable for testing purposes.
+ V8_EXPORT_PRIVATE static base::TimeTicks (*Now)();
+
+ // Helper to switch over to CPU time.
+ static base::TimeTicks NowCPUTime();
+
+ private:
+ inline void Pause(base::TimeTicks now) {
+ DCHECK(IsStarted());
+ elapsed_ += (now - start_ticks_);
+ start_ticks_ = base::TimeTicks();
+ }
+
+ inline void Resume(base::TimeTicks now) {
+ DCHECK(!IsStarted());
+ start_ticks_ = now;
+ }
+
+ inline void CommitTimeToCounter() {
+ counter_->Add(elapsed_);
+ elapsed_ = base::TimeDelta();
+ }
+
+ RuntimeCallCounter* counter_ = nullptr;
+ base::AtomicValue<RuntimeCallTimer*> parent_;
+ base::TimeTicks start_ticks_;
+ base::TimeDelta elapsed_;
+};
+
+#define FOR_EACH_GC_COUNTER(V) \
+ TRACER_SCOPES(V) \
+ TRACER_BACKGROUND_SCOPES(V)
+
+#define FOR_EACH_API_COUNTER(V) \
+ V(AccessorPair_New) \
+ V(ArrayBuffer_Cast) \
+ V(ArrayBuffer_Detach) \
+ V(ArrayBuffer_New) \
+ V(ArrayBuffer_NewBackingStore) \
+ V(ArrayBuffer_BackingStore_Reallocate) \
+ V(Array_CloneElementAt) \
+ V(Array_New) \
+ V(BigInt64Array_New) \
+ V(BigInt_NewFromWords) \
+ V(BigIntObject_BigIntValue) \
+ V(BigIntObject_New) \
+ V(BigUint64Array_New) \
+ V(BooleanObject_BooleanValue) \
+ V(BooleanObject_New) \
+ V(Context_New) \
+ V(Context_NewRemoteContext) \
+ V(DataView_New) \
+ V(Date_New) \
+ V(Date_NumberValue) \
+ V(Debug_Call) \
+ V(debug_GetPrivateMembers) \
+ V(Error_New) \
+ V(External_New) \
+ V(Float32Array_New) \
+ V(Float64Array_New) \
+ V(Function_Call) \
+ V(Function_New) \
+ V(Function_FunctionProtoToString) \
+ V(Function_NewInstance) \
+ V(FunctionTemplate_GetFunction) \
+ V(FunctionTemplate_New) \
+ V(FunctionTemplate_NewRemoteInstance) \
+ V(FunctionTemplate_NewWithCache) \
+ V(FunctionTemplate_NewWithFastHandler) \
+ V(Int16Array_New) \
+ V(Int32Array_New) \
+ V(Int8Array_New) \
+ V(Isolate_DateTimeConfigurationChangeNotification) \
+ V(Isolate_LocaleConfigurationChangeNotification) \
+ V(JSON_Parse) \
+ V(JSON_Stringify) \
+ V(Map_AsArray) \
+ V(Map_Clear) \
+ V(Map_Delete) \
+ V(Map_Get) \
+ V(Map_Has) \
+ V(Map_New) \
+ V(Map_Set) \
+ V(Message_GetEndColumn) \
+ V(Message_GetLineNumber) \
+ V(Message_GetSourceLine) \
+ V(Message_GetStartColumn) \
+ V(Module_Evaluate) \
+ V(Module_InstantiateModule) \
+ V(Module_SetSyntheticModuleExport) \
+ V(NumberObject_New) \
+ V(NumberObject_NumberValue) \
+ V(Object_CallAsConstructor) \
+ V(Object_CallAsFunction) \
+ V(Object_CreateDataProperty) \
+ V(Object_DefineOwnProperty) \
+ V(Object_DefineProperty) \
+ V(Object_Delete) \
+ V(Object_DeleteProperty) \
+ V(Object_ForceSet) \
+ V(Object_Get) \
+ V(Object_GetOwnPropertyDescriptor) \
+ V(Object_GetOwnPropertyNames) \
+ V(Object_GetPropertyAttributes) \
+ V(Object_GetPropertyNames) \
+ V(Object_GetRealNamedProperty) \
+ V(Object_GetRealNamedPropertyAttributes) \
+ V(Object_GetRealNamedPropertyAttributesInPrototypeChain) \
+ V(Object_GetRealNamedPropertyInPrototypeChain) \
+ V(Object_Has) \
+ V(Object_HasOwnProperty) \
+ V(Object_HasRealIndexedProperty) \
+ V(Object_HasRealNamedCallbackProperty) \
+ V(Object_HasRealNamedProperty) \
+ V(Object_IsCodeLike) \
+ V(Object_New) \
+ V(Object_ObjectProtoToString) \
+ V(Object_Set) \
+ V(Object_SetAccessor) \
+ V(Object_SetIntegrityLevel) \
+ V(Object_SetPrivate) \
+ V(Object_SetPrototype) \
+ V(ObjectTemplate_New) \
+ V(ObjectTemplate_NewInstance) \
+ V(Object_ToArrayIndex) \
+ V(Object_ToBigInt) \
+ V(Object_ToDetailString) \
+ V(Object_ToInt32) \
+ V(Object_ToInteger) \
+ V(Object_ToNumber) \
+ V(Object_ToObject) \
+ V(Object_ToString) \
+ V(Object_ToUint32) \
+ V(Persistent_New) \
+ V(Private_New) \
+ V(Promise_Catch) \
+ V(Promise_Chain) \
+ V(Promise_HasRejectHandler) \
+ V(Promise_Resolver_New) \
+ V(Promise_Resolver_Reject) \
+ V(Promise_Resolver_Resolve) \
+ V(Promise_Result) \
+ V(Promise_Status) \
+ V(Promise_Then) \
+ V(Proxy_New) \
+ V(RangeError_New) \
+ V(ReferenceError_New) \
+ V(RegExp_Exec) \
+ V(RegExp_New) \
+ V(ScriptCompiler_Compile) \
+ V(ScriptCompiler_CompileFunctionInContext) \
+ V(ScriptCompiler_CompileUnbound) \
+ V(Script_Run) \
+ V(Set_Add) \
+ V(Set_AsArray) \
+ V(Set_Clear) \
+ V(Set_Delete) \
+ V(Set_Has) \
+ V(Set_New) \
+ V(SharedArrayBuffer_New) \
+ V(SharedArrayBuffer_NewBackingStore) \
+ V(String_Concat) \
+ V(String_NewExternalOneByte) \
+ V(String_NewExternalTwoByte) \
+ V(String_NewFromOneByte) \
+ V(String_NewFromTwoByte) \
+ V(String_NewFromUtf8) \
+ V(String_NewFromUtf8Literal) \
+ V(StringObject_New) \
+ V(StringObject_StringValue) \
+ V(String_Write) \
+ V(String_WriteUtf8) \
+ V(Symbol_New) \
+ V(SymbolObject_New) \
+ V(SymbolObject_SymbolValue) \
+ V(SyntaxError_New) \
+ V(TracedGlobal_New) \
+ V(TryCatch_StackTrace) \
+ V(TypeError_New) \
+ V(Uint16Array_New) \
+ V(Uint32Array_New) \
+ V(Uint8Array_New) \
+ V(Uint8ClampedArray_New) \
+ V(UnboundScript_GetId) \
+ V(UnboundScript_GetLineNumber) \
+ V(UnboundScript_GetName) \
+ V(UnboundScript_GetSourceMappingURL) \
+ V(UnboundScript_GetSourceURL) \
+ V(ValueDeserializer_ReadHeader) \
+ V(ValueDeserializer_ReadValue) \
+ V(ValueSerializer_WriteValue) \
+ V(Value_Equals) \
+ V(Value_InstanceOf) \
+ V(Value_Int32Value) \
+ V(Value_IntegerValue) \
+ V(Value_NumberValue) \
+ V(Value_TypeOf) \
+ V(Value_Uint32Value) \
+ V(WasmCompileError_New) \
+ V(WasmLinkError_New) \
+ V(WasmRuntimeError_New) \
+ V(WeakMap_Get) \
+ V(WeakMap_New) \
+ V(WeakMap_Set)
+
+#define ADD_THREAD_SPECIFIC_COUNTER(V, Prefix, Suffix) \
+ V(Prefix##Suffix) \
+ V(Prefix##Background##Suffix)
+
+#define FOR_EACH_THREAD_SPECIFIC_COUNTER(V) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Compile, Analyse) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Compile, Eval) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Compile, Function) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Compile, Ignition) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Compile, IgnitionFinalization) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Compile, RewriteReturnResult) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Compile, ScopeAnalysis) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Compile, Script) \
+ \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, AllocateFPRegisters) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, AllocateGeneralRegisters) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, AssembleCode) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, AssignSpillSlots) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, BuildLiveRangeBundles) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, BuildLiveRanges) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, BytecodeGraphBuilder) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, CommitAssignment) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, ConnectRanges) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, ControlFlowOptimization) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, CSAEarlyOptimization) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, CSAOptimization) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, DecideSpillingMode) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, DecompressionOptimization) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, EarlyOptimization) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, EarlyTrimming) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, EffectLinearization) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, EscapeAnalysis) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, FinalizeCode) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, FrameElision) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, GenericLowering) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, Inlining) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, JumpThreading) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, MidTierPopulateReferenceMaps) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, MidTierRegisterAllocator) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, MidTierRegisterOutputDefinition) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, MidTierSpillSlotAllocator) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, LateGraphTrimming) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, LateOptimization) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, LoadElimination) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, LocateSpillSlots) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, LoopExitElimination) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, LoopPeeling) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, MachineOperatorOptimization) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, MeetRegisterConstraints) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, MemoryOptimization) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, OptimizeMoves) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, PopulatePointerMaps) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, PrintGraph) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, ResolveControlFlow) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, ResolvePhis) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, \
+ ScheduledEffectControlLinearization) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, ScheduledMachineLowering) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, Scheduling) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, SelectInstructions) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, SimplifiedLowering) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, StoreStoreElimination) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, TypeAssertions) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, TypedLowering) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, Typer) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, Untyper) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, VerifyGraph) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, WasmBaseOptimization) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, WasmInlining) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, WasmLoopUnrolling) \
+ \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Parse, ArrowFunctionLiteral) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Parse, FunctionLiteral) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, Parse, Program) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, PreParse, ArrowFunctionLiteral) \
+ ADD_THREAD_SPECIFIC_COUNTER(V, PreParse, WithVariableResolution)
+
+#define FOR_EACH_MANUAL_COUNTER(V) \
+ V(AccessorGetterCallback) \
+ V(AccessorSetterCallback) \
+ V(ArrayLengthGetter) \
+ V(ArrayLengthSetter) \
+ V(BoundFunctionLengthGetter) \
+ V(BoundFunctionNameGetter) \
+ V(CodeGenerationFromStringsCallbacks) \
+ V(CompileBackgroundCompileTask) \
+ V(CompileBaseline) \
+ V(CompileBaselineVisit) \
+ V(CompileBaselinePreVisit) \
+ V(CompileCollectSourcePositions) \
+ V(CompileDeserialize) \
+ V(CompileEnqueueOnDispatcher) \
+ V(CompileFinalizeBackgroundCompileTask) \
+ V(CompileFinishNowOnDispatcher) \
+ V(CompileGetFromOptimizedCodeMap) \
+ V(CompilePublishBackgroundFinalization) \
+ V(CompileSerialize) \
+ V(CompileWaitForDispatcher) \
+ V(ConfigureInstance) \
+ V(CreateApiFunction) \
+ V(DeoptimizeCode) \
+ V(DeserializeContext) \
+ V(DeserializeIsolate) \
+ V(FinalizationRegistryCleanupFromTask) \
+ V(FunctionCallback) \
+ V(FunctionLengthGetter) \
+ V(FunctionPrototypeGetter) \
+ V(FunctionPrototypeSetter) \
+ V(GC_Custom_AllAvailableGarbage) \
+ V(GC_Custom_IncrementalMarkingObserver) \
+ V(GC_Custom_SlowAllocateRaw) \
+ V(GCEpilogueCallback) \
+ V(GCPrologueCallback) \
+ V(Genesis) \
+ V(GetCompatibleReceiver) \
+ V(GetMoreDataCallback) \
+ V(IndexedDefinerCallback) \
+ V(IndexedDeleterCallback) \
+ V(IndexedDescriptorCallback) \
+ V(IndexedEnumeratorCallback) \
+ V(IndexedGetterCallback) \
+ V(IndexedQueryCallback) \
+ V(IndexedSetterCallback) \
+ V(InstantiateFunction) \
+ V(InstantiateObject) \
+ V(Invoke) \
+ V(InvokeApiFunction) \
+ V(InvokeApiInterruptCallbacks) \
+ V(IsCompatibleReceiver) \
+ V(IsCompatibleReceiverMap) \
+ V(IsTemplateFor) \
+ V(JS_Execution) \
+ V(Map_SetPrototype) \
+ V(Map_TransitionToAccessorProperty) \
+ V(Map_TransitionToDataProperty) \
+ V(MessageListenerCallback) \
+ V(NamedDefinerCallback) \
+ V(NamedDeleterCallback) \
+ V(NamedDescriptorCallback) \
+ V(NamedEnumeratorCallback) \
+ V(NamedGetterCallback) \
+ V(NamedQueryCallback) \
+ V(NamedSetterCallback) \
+ V(Object_DeleteProperty) \
+ V(ObjectVerify) \
+ V(OptimizeBackgroundDispatcherJob) \
+ V(OptimizeCode) \
+ V(OptimizeConcurrentFinalize) \
+ V(OptimizeConcurrentPrepare) \
+ V(OptimizeFinalizePipelineJob) \
+ V(OptimizeHeapBrokerInitialization) \
+ V(OptimizeNonConcurrent) \
+ V(OptimizeSerialization) \
+ V(OptimizeSerializeMetadata) \
+ V(ParseEval) \
+ V(ParseFunction) \
+ V(PropertyCallback) \
+ V(PrototypeMap_TransitionToAccessorProperty) \
+ V(PrototypeMap_TransitionToDataProperty) \
+ V(PrototypeObject_DeleteProperty) \
+ V(ReconfigureToDataProperty) \
+ V(UpdateProtector) \
+ V(StringLengthGetter) \
+ V(TestCounter1) \
+ V(TestCounter2) \
+ V(TestCounter3)
+
+#define FOR_EACH_HANDLER_COUNTER(V) \
+ V(KeyedLoadIC_KeyedLoadSloppyArgumentsStub) \
+ V(KeyedLoadIC_LoadElementDH) \
+ V(KeyedLoadIC_LoadIndexedInterceptorStub) \
+ V(KeyedLoadIC_LoadIndexedStringDH) \
+ V(KeyedLoadIC_SlowStub) \
+ V(KeyedStoreIC_ElementsTransitionAndStoreStub) \
+ V(KeyedStoreIC_KeyedStoreSloppyArgumentsStub) \
+ V(KeyedStoreIC_SlowStub) \
+ V(KeyedStoreIC_StoreElementStub) \
+ V(KeyedStoreIC_StoreFastElementStub) \
+ V(LoadGlobalIC_LoadScriptContextField) \
+ V(LoadGlobalIC_SlowStub) \
+ V(LoadIC_FunctionPrototypeStub) \
+ V(LoadIC_HandlerCacheHit_Accessor) \
+ V(LoadIC_LoadAccessorDH) \
+ V(LoadIC_LoadAccessorFromPrototypeDH) \
+ V(LoadIC_LoadApiGetterFromPrototypeDH) \
+ V(LoadIC_LoadCallback) \
+ V(LoadIC_LoadConstantDH) \
+ V(LoadIC_LoadConstantFromPrototypeDH) \
+ V(LoadIC_LoadFieldDH) \
+ V(LoadIC_LoadFieldFromPrototypeDH) \
+ V(LoadIC_LoadGlobalDH) \
+ V(LoadIC_LoadGlobalFromPrototypeDH) \
+ V(LoadIC_LoadIntegerIndexedExoticDH) \
+ V(LoadIC_LoadInterceptorDH) \
+ V(LoadIC_LoadInterceptorFromPrototypeDH) \
+ V(LoadIC_LoadNativeDataPropertyDH) \
+ V(LoadIC_LoadNativeDataPropertyFromPrototypeDH) \
+ V(LoadIC_LoadNonexistentDH) \
+ V(LoadIC_LoadNonMaskingInterceptorDH) \
+ V(LoadIC_LoadNormalDH) \
+ V(LoadIC_LoadNormalFromPrototypeDH) \
+ V(LoadIC_NonReceiver) \
+ V(LoadIC_SlowStub) \
+ V(LoadIC_StringLength) \
+ V(LoadIC_StringWrapperLength) \
+ V(StoreGlobalIC_SlowStub) \
+ V(StoreGlobalIC_StoreScriptContextField) \
+ V(StoreIC_HandlerCacheHit_Accessor) \
+ V(StoreIC_NonReceiver) \
+ V(StoreIC_SlowStub) \
+ V(StoreIC_StoreAccessorDH) \
+ V(StoreIC_StoreAccessorOnPrototypeDH) \
+ V(StoreIC_StoreApiSetterOnPrototypeDH) \
+ V(StoreIC_StoreFieldDH) \
+ V(StoreIC_StoreGlobalDH) \
+ V(StoreIC_StoreGlobalTransitionDH) \
+ V(StoreIC_StoreInterceptorStub) \
+ V(StoreIC_StoreNativeDataPropertyDH) \
+ V(StoreIC_StoreNativeDataPropertyOnPrototypeDH) \
+ V(StoreIC_StoreNormalDH) \
+ V(StoreIC_StoreTransitionDH) \
+ V(StoreInArrayLiteralIC_SlowStub)
+
+enum RuntimeCallCounterId {
+#define CALL_RUNTIME_COUNTER(name) kGC_##name,
+ FOR_EACH_GC_COUNTER(CALL_RUNTIME_COUNTER)
+#undef CALL_RUNTIME_COUNTER
+#define CALL_RUNTIME_COUNTER(name) k##name,
+ FOR_EACH_MANUAL_COUNTER(CALL_RUNTIME_COUNTER)
+#undef CALL_RUNTIME_COUNTER
+#define CALL_RUNTIME_COUNTER(name, nargs, ressize) kRuntime_##name,
+ FOR_EACH_INTRINSIC(CALL_RUNTIME_COUNTER)
+#undef CALL_RUNTIME_COUNTER
+#define CALL_BUILTIN_COUNTER(name) kBuiltin_##name,
+ BUILTIN_LIST_C(CALL_BUILTIN_COUNTER)
+#undef CALL_BUILTIN_COUNTER
+#define CALL_BUILTIN_COUNTER(name) kAPI_##name,
+ FOR_EACH_API_COUNTER(CALL_BUILTIN_COUNTER)
+#undef CALL_BUILTIN_COUNTER
+#define CALL_BUILTIN_COUNTER(name) kHandler_##name,
+ FOR_EACH_HANDLER_COUNTER(CALL_BUILTIN_COUNTER)
+#undef CALL_BUILTIN_COUNTER
+#define THREAD_SPECIFIC_COUNTER(name) k##name,
+ FOR_EACH_THREAD_SPECIFIC_COUNTER(
+ THREAD_SPECIFIC_COUNTER)
+#undef THREAD_SPECIFIC_COUNTER
+ kNumberOfCounters,
+};
+
+class RuntimeCallStats final {
+ public:
+ enum ThreadType { kMainIsolateThread, kWorkerThread };
+
+ // If kExact is chosen the counter will be use as given. With kThreadSpecific,
+ // if the RuntimeCallStats was created for a worker thread, then the
+ // background specific version of the counter will be used instead.
+ enum CounterMode { kExact, kThreadSpecific };
+
+ explicit V8_EXPORT_PRIVATE RuntimeCallStats(ThreadType thread_type);
+
+ // Starting measuring the time for a function. This will establish the
+ // connection to the parent counter for properly calculating the own times.
+ V8_EXPORT_PRIVATE void Enter(RuntimeCallTimer* timer,
+ RuntimeCallCounterId counter_id);
+
+ // Leave a scope for a measured runtime function. This will properly add
+ // the time delta to the current_counter and subtract the delta from its
+ // parent.
+ V8_EXPORT_PRIVATE void Leave(RuntimeCallTimer* timer);
+
+ // Set counter id for the innermost measurement. It can be used to refine
+ // event kind when a runtime entry counter is too generic.
+ V8_EXPORT_PRIVATE void CorrectCurrentCounterId(
+ RuntimeCallCounterId counter_id, CounterMode mode = kExact);
+
+ V8_EXPORT_PRIVATE void Reset();
+ // Add all entries from another stats object.
+ void Add(RuntimeCallStats* other);
+ V8_EXPORT_PRIVATE void Print(std::ostream& os);
+ V8_EXPORT_PRIVATE void Print();
+ V8_NOINLINE void Dump(v8::tracing::TracedValue* value);
+
+ V8_EXPORT_PRIVATE void EnumerateCounters(
+ debug::RuntimeCallCounterCallback callback);
+
+ ThreadId thread_id() const { return thread_id_; }
+ RuntimeCallTimer* current_timer() { return current_timer_.Value(); }
+ RuntimeCallCounter* current_counter() { return current_counter_.Value(); }
+ bool InUse() { return in_use_; }
+ bool IsCalledOnTheSameThread();
+
+ V8_EXPORT_PRIVATE bool IsBackgroundThreadSpecificVariant(
+ RuntimeCallCounterId id);
+ V8_EXPORT_PRIVATE bool HasThreadSpecificCounterVariants(
+ RuntimeCallCounterId id);
+
+ // This should only be called for counters with a dual Background variant. If
+ // on the main thread, this just returns the counter. If on a worker thread,
+ // it returns Background variant of the counter.
+ RuntimeCallCounterId CounterIdForThread(RuntimeCallCounterId id) {
+ DCHECK(HasThreadSpecificCounterVariants(id));
+ // All thread specific counters are laid out with the main thread variant
+ // first followed by the background variant.
+ return thread_type_ == kWorkerThread
+ ? static_cast<RuntimeCallCounterId>(id + 1)
+ : id;
+ }
+
+ bool IsCounterAppropriateForThread(RuntimeCallCounterId id) {
+ // TODO(delphick): We should add background-only counters and ensure that
+ // all counters (not just the thread-specific variants) are only invoked on
+ // the correct thread.
+ if (!HasThreadSpecificCounterVariants(id)) return true;
+ return IsBackgroundThreadSpecificVariant(id) ==
+ (thread_type_ == kWorkerThread);
+ }
+
+ static const int kNumberOfCounters =
+ static_cast<int>(RuntimeCallCounterId::kNumberOfCounters);
+ RuntimeCallCounter* GetCounter(RuntimeCallCounterId counter_id) {
+ return &counters_[static_cast<int>(counter_id)];
+ }
+ RuntimeCallCounter* GetCounter(int counter_id) {
+ return &counters_[counter_id];
+ }
+
+ private:
+ // Top of a stack of active timers.
+ base::AtomicValue<RuntimeCallTimer*> current_timer_;
+ // Active counter object associated with current timer.
+ base::AtomicValue<RuntimeCallCounter*> current_counter_;
+ // Used to track nested tracing scopes.
+ bool in_use_;
+ ThreadType thread_type_;
+ ThreadId thread_id_;
+ RuntimeCallCounter counters_[kNumberOfCounters];
+};
+
+class WorkerThreadRuntimeCallStats final {
+ public:
+ WorkerThreadRuntimeCallStats();
+ ~WorkerThreadRuntimeCallStats();
+
+ // Returns the TLS key associated with this WorkerThreadRuntimeCallStats.
+ base::Thread::LocalStorageKey GetKey();
+
+ // Returns a new worker thread runtime call stats table managed by this
+ // WorkerThreadRuntimeCallStats.
+ RuntimeCallStats* NewTable();
+
+ // Adds the counters from the worker thread tables to |main_call_stats|.
+ void AddToMainTable(RuntimeCallStats* main_call_stats);
+
+ private:
+ base::Mutex mutex_;
+ std::vector<std::unique_ptr<RuntimeCallStats>> tables_;
+ base::Optional<base::Thread::LocalStorageKey> tls_key_;
+ // Since this is for creating worker thread runtime-call stats, record the
+ // main thread ID to ensure we never create a worker RCS table for the main
+ // thread.
+ ThreadId isolate_thread_id_;
+};
+
+// Creating a WorkerThreadRuntimeCallStatsScope will provide a thread-local
+// runtime call stats table, and will dump the table to an immediate trace event
+// when it is destroyed.
+class V8_NODISCARD WorkerThreadRuntimeCallStatsScope final {
+ public:
+ explicit WorkerThreadRuntimeCallStatsScope(
+ WorkerThreadRuntimeCallStats* off_thread_stats);
+ ~WorkerThreadRuntimeCallStatsScope();
+
+ RuntimeCallStats* Get() const { return table_; }
+
+ private:
+ RuntimeCallStats* table_;
+};
+
+#define CHANGE_CURRENT_RUNTIME_COUNTER(runtime_call_stats, counter_id) \
+ do { \
+ if (V8_UNLIKELY(TracingFlags::is_runtime_stats_enabled()) && \
+ runtime_call_stats) { \
+ runtime_call_stats->CorrectCurrentCounterId(counter_id); \
+ } \
+ } while (false)
+
+#define TRACE_HANDLER_STATS(isolate, counter_name) \
+ CHANGE_CURRENT_RUNTIME_COUNTER( \
+ isolate->counters()->runtime_call_stats(), \
+ RuntimeCallCounterId::kHandler_##counter_name)
+
+// A RuntimeCallTimerScopes wraps around a RuntimeCallTimer to measure the
+// the time of C++ scope.
+class V8_NODISCARD RuntimeCallTimerScope {
+ public:
+ inline RuntimeCallTimerScope(Isolate* isolate,
+ RuntimeCallCounterId counter_id);
+ inline RuntimeCallTimerScope(RuntimeCallStats* stats,
+ RuntimeCallCounterId counter_id,
+ RuntimeCallStats::CounterMode mode =
+ RuntimeCallStats::CounterMode::kExact) {
+ if (V8_LIKELY(!TracingFlags::is_runtime_stats_enabled() ||
+ stats == nullptr)) {
+ return;
+ }
+ stats_ = stats;
+ if (mode == RuntimeCallStats::CounterMode::kThreadSpecific) {
+ counter_id = stats->CounterIdForThread(counter_id);
+ }
+
+ DCHECK(stats->IsCounterAppropriateForThread(counter_id));
+ stats_->Enter(&timer_, counter_id);
+ }
+
+ inline ~RuntimeCallTimerScope() {
+ if (V8_UNLIKELY(stats_ != nullptr)) {
+ stats_->Leave(&timer_);
+ }
+ }
+
+ RuntimeCallTimerScope(const RuntimeCallTimerScope&) = delete;
+ RuntimeCallTimerScope& operator=(const RuntimeCallTimerScope&) = delete;
+
+ private:
+ RuntimeCallStats* stats_ = nullptr;
+ RuntimeCallTimer timer_;
+};
+
+#else // RUNTIME_CALL_STATS
+
+#define RCS_SCOPE(...)
+#define TRACE_HANDLER_STATS(...)
+#define CHANGE_CURRENT_RUNTIME_COUNTER(...)
+
+// Create dummy types to limit code changes
+class WorkerThreadRuntimeCallStats {};
+
+class RuntimeCallStats {
+ public:
+ enum ThreadType { kMainIsolateThread, kWorkerThread };
+ explicit V8_EXPORT_PRIVATE RuntimeCallStats(ThreadType thread_type) {}
+};
+
+class WorkerThreadRuntimeCallStatsScope {
+ public:
+ explicit WorkerThreadRuntimeCallStatsScope(
+ WorkerThreadRuntimeCallStats* off_thread_stats) {}
+ RuntimeCallStats* Get() const { return nullptr; }
+};
+
+#endif // RUNTIME_CALL_STATS
+
+} // namespace internal
+} // namespace v8
+
+#endif // V8_LOGGING_RUNTIME_CALL_STATS_H_