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