1 // Copyright 2015 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_TRACING_TRACE_EVENT_H_
6 #define V8_TRACING_TRACE_EVENT_H_
7 
8 #include <stddef.h>
9 #include <memory>
10 
11 // Include first to ensure that V8_USE_PERFETTO can be defined before use.
12 #include "v8config.h"  // NOLINT(build/include_directory)
13 
14 #if defined(V8_USE_PERFETTO)
15 #include "protos/perfetto/trace/track_event/debug_annotation.pbzero.h"
16 #include "src/tracing/trace-categories.h"
17 #else
18 #include "base/trace_event/common/trace_event_common.h"
19 #endif  // !defined(V8_USE_PERFETTO)
20 
21 #include "include/v8-platform.h"
22 #include "src/base/atomicops.h"
23 #include "src/base/macros.h"
24 #include "src/base/platform/wrappers.h"
25 
26 // This header file defines implementation details of how the trace macros in
27 // trace_event_common.h collect and store trace events. Anything not
28 // implementation-specific should go in trace_macros_common.h instead of here.
29 
30 
31 // The pointer returned from GetCategoryGroupEnabled() points to a
32 // value with zero or more of the following bits. Used in this class only.
33 // The TRACE_EVENT macros should only use the value as a bool.
34 // These values must be in sync with macro values in trace_log.h in
35 // chromium.
36 enum CategoryGroupEnabledFlags {
37   // Category group enabled for the recording mode.
38   kEnabledForRecording_CategoryGroupEnabledFlags = 1 << 0,
39   // Category group enabled by SetEventCallbackEnabled().
40   kEnabledForEventCallback_CategoryGroupEnabledFlags = 1 << 2,
41   // Category group enabled to export events to ETW.
42   kEnabledForETWExport_CategoryGroupEnabledFlags = 1 << 3,
43 };
44 
45 #if !defined(V8_USE_PERFETTO)
46 
47 // TODO(petermarshall): Remove with the old tracing implementation - Perfetto
48 // copies const char* arguments by default.
49 // By default, const char* argument values are assumed to have long-lived scope
50 // and will not be copied. Use this macro to force a const char* to be copied.
51 #define TRACE_STR_COPY(str) v8::internal::tracing::TraceStringWithCopy(str)
52 
53 // By default, trace IDs are eventually converted to a single 64-bit number. Use
54 // this macro to add a scope string.
55 #define TRACE_ID_WITH_SCOPE(scope, id) \
56   v8::internal::tracing::TraceID::WithScope(scope, id)
57 
58 #define INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE() \
59   TRACE_EVENT_API_LOAD_CATEGORY_GROUP_ENABLED() &                        \
60       (kEnabledForRecording_CategoryGroupEnabledFlags |                  \
61        kEnabledForEventCallback_CategoryGroupEnabledFlags)
62 
63 // The following macro has no implementation, but it needs to exist since
64 // it gets called from scoped trace events. It cannot call UNIMPLEMENTED()
65 // since an empty implementation is a valid one.
66 #define INTERNAL_TRACE_MEMORY(category, name)
67 
68 ////////////////////////////////////////////////////////////////////////////////
69 // Implementation specific tracing API definitions.
70 
71 // Get a pointer to the enabled state of the given trace category. Only
72 // long-lived literal strings should be given as the category group. The
73 // returned pointer can be held permanently in a local static for example. If
74 // the unsigned char is non-zero, tracing is enabled. If tracing is enabled,
75 // TRACE_EVENT_API_ADD_TRACE_EVENT can be called. It's OK if tracing is disabled
76 // between the load of the tracing state and the call to
77 // TRACE_EVENT_API_ADD_TRACE_EVENT, because this flag only provides an early out
78 // for best performance when tracing is disabled.
79 // const uint8_t*
80 //     TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(const char* category_group)
81 #define TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED                \
82   v8::internal::tracing::TraceEventHelper::GetTracingController() \
83       ->GetCategoryGroupEnabled
84 
85 // Get the number of times traces have been recorded. This is used to implement
86 // the TRACE_EVENT_IS_NEW_TRACE facility.
87 // unsigned int TRACE_EVENT_API_GET_NUM_TRACES_RECORDED()
88 #define TRACE_EVENT_API_GET_NUM_TRACES_RECORDED UNIMPLEMENTED()
89 
90 // Add a trace event to the platform tracing system.
91 // uint64_t TRACE_EVENT_API_ADD_TRACE_EVENT(
92 //                    char phase,
93 //                    const uint8_t* category_group_enabled,
94 //                    const char* name,
95 //                    const char* scope,
96 //                    uint64_t id,
97 //                    uint64_t bind_id,
98 //                    int num_args,
99 //                    const char** arg_names,
100 //                    const uint8_t* arg_types,
101 //                    const uint64_t* arg_values,
102 //                    unsigned int flags)
103 #define TRACE_EVENT_API_ADD_TRACE_EVENT v8::internal::tracing::AddTraceEventImpl
104 
105 // Add a trace event to the platform tracing system.
106 // uint64_t TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_TIMESTAMP(
107 //                    char phase,
108 //                    const uint8_t* category_group_enabled,
109 //                    const char* name,
110 //                    const char* scope,
111 //                    uint64_t id,
112 //                    uint64_t bind_id,
113 //                    int num_args,
114 //                    const char** arg_names,
115 //                    const uint8_t* arg_types,
116 //                    const uint64_t* arg_values,
117 //                    unsigned int flags,
118 //                    int64_t timestamp)
119 #define TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_TIMESTAMP \
120   v8::internal::tracing::AddTraceEventWithTimestampImpl
121 
122 // Set the duration field of a COMPLETE trace event.
123 // void TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(
124 //     const uint8_t* category_group_enabled,
125 //     const char* name,
126 //     uint64_t id)
127 #define TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION               \
128   v8::internal::tracing::TraceEventHelper::GetTracingController() \
129       ->UpdateTraceEventDuration
130 
131 // Defines atomic operations used internally by the tracing system.
132 #define TRACE_EVENT_API_ATOMIC_WORD v8::base::AtomicWord
133 #define TRACE_EVENT_API_ATOMIC_LOAD(var) v8::base::Relaxed_Load(&(var))
134 #define TRACE_EVENT_API_ATOMIC_STORE(var, value) \
135   v8::base::Relaxed_Store(&(var), (value))
136 #define TRACE_EVENT_API_LOAD_CATEGORY_GROUP_ENABLED()                \
137   v8::base::Relaxed_Load(reinterpret_cast<const v8::base::Atomic8*>( \
138       INTERNAL_TRACE_EVENT_UID(category_group_enabled)))
139 
140 ////////////////////////////////////////////////////////////////////////////////
141 
142 // Implementation detail: trace event macros create temporary variables
143 // to keep instrumentation overhead low. These macros give each temporary
144 // variable a unique name based on the line number to prevent name collisions.
145 #define INTERNAL_TRACE_EVENT_UID3(a, b) trace_event_unique_##a##b
146 #define INTERNAL_TRACE_EVENT_UID2(a, b) INTERNAL_TRACE_EVENT_UID3(a, b)
147 #define INTERNAL_TRACE_EVENT_UID(name_prefix) \
148   INTERNAL_TRACE_EVENT_UID2(name_prefix, __LINE__)
149 
150 // Implementation detail: internal macro to create static category.
151 // No barriers are needed, because this code is designed to operate safely
152 // even when the unsigned char* points to garbage data (which may be the case
153 // on processors without cache coherency).
154 // TODO(fmeawad): This implementation contradicts that we can have a different
155 // configuration for each isolate,
156 // https://code.google.com/p/v8/issues/detail?id=4563
157 #define INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO_CUSTOM_VARIABLES(             \
158     category_group, atomic, category_group_enabled)                          \
159   category_group_enabled =                                                   \
160       reinterpret_cast<const uint8_t*>(TRACE_EVENT_API_ATOMIC_LOAD(atomic)); \
161   if (!category_group_enabled) {                                             \
162     category_group_enabled =                                                 \
163         TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(category_group);          \
164     TRACE_EVENT_API_ATOMIC_STORE(                                            \
165         atomic, reinterpret_cast<TRACE_EVENT_API_ATOMIC_WORD>(               \
166                     category_group_enabled));                                \
167   }
168 
169 #define INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group)             \
170   static TRACE_EVENT_API_ATOMIC_WORD INTERNAL_TRACE_EVENT_UID(atomic) = 0; \
171   const uint8_t* INTERNAL_TRACE_EVENT_UID(category_group_enabled);         \
172   INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO_CUSTOM_VARIABLES(                 \
173       category_group, INTERNAL_TRACE_EVENT_UID(atomic),                    \
174       INTERNAL_TRACE_EVENT_UID(category_group_enabled));
175 
176 // Implementation detail: internal macro to create static category and add
177 // event if the category is enabled.
178 #define INTERNAL_TRACE_EVENT_ADD(phase, category_group, name, flags, ...)    \
179   do {                                                                       \
180     INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group);                  \
181     if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) {  \
182       v8::internal::tracing::AddTraceEvent(                                  \
183           phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), name,     \
184           v8::internal::tracing::kGlobalScope, v8::internal::tracing::kNoId, \
185           v8::internal::tracing::kNoId, flags, ##__VA_ARGS__);               \
186     }                                                                        \
187   } while (false)
188 
189 // Implementation detail: internal macro to create static category and add begin
190 // event if the category is enabled. Also adds the end event when the scope
191 // ends.
192 #define INTERNAL_TRACE_EVENT_ADD_SCOPED(category_group, name, ...)           \
193   INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group);                    \
194   v8::internal::tracing::ScopedTracer INTERNAL_TRACE_EVENT_UID(tracer);      \
195   if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) {    \
196     uint64_t h = v8::internal::tracing::AddTraceEvent(                       \
197         TRACE_EVENT_PHASE_COMPLETE,                                          \
198         INTERNAL_TRACE_EVENT_UID(category_group_enabled), name,              \
199         v8::internal::tracing::kGlobalScope, v8::internal::tracing::kNoId,   \
200         v8::internal::tracing::kNoId, TRACE_EVENT_FLAG_NONE, ##__VA_ARGS__); \
201     INTERNAL_TRACE_EVENT_UID(tracer)                                         \
202         .Initialize(INTERNAL_TRACE_EVENT_UID(category_group_enabled), name,  \
203                     h);                                                      \
204   }
205 
206 #define INTERNAL_TRACE_EVENT_ADD_SCOPED_WITH_FLOW(category_group, name,     \
207                                                   bind_id, flow_flags, ...) \
208   INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group);                   \
209   v8::internal::tracing::ScopedTracer INTERNAL_TRACE_EVENT_UID(tracer);     \
210   if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) {   \
211     unsigned int trace_event_flags = flow_flags;                            \
212     v8::internal::tracing::TraceID trace_event_bind_id(bind_id,             \
213                                                        &trace_event_flags); \
214     uint64_t h = v8::internal::tracing::AddTraceEvent(                      \
215         TRACE_EVENT_PHASE_COMPLETE,                                         \
216         INTERNAL_TRACE_EVENT_UID(category_group_enabled), name,             \
217         v8::internal::tracing::kGlobalScope, v8::internal::tracing::kNoId,  \
218         trace_event_bind_id.raw_id(), trace_event_flags, ##__VA_ARGS__);    \
219     INTERNAL_TRACE_EVENT_UID(tracer)                                        \
220         .Initialize(INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, \
221                     h);                                                     \
222   }
223 
224 // Implementation detail: internal macro to create static category and add
225 // event if the category is enabled.
226 #define INTERNAL_TRACE_EVENT_ADD_WITH_ID(phase, category_group, name, id,      \
227                                          flags, ...)                           \
228   do {                                                                         \
229     INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group);                    \
230     if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) {    \
231       unsigned int trace_event_flags = flags | TRACE_EVENT_FLAG_HAS_ID;        \
232       v8::internal::tracing::TraceID trace_event_trace_id(id,                  \
233                                                           &trace_event_flags); \
234       v8::internal::tracing::AddTraceEvent(                                    \
235           phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), name,       \
236           trace_event_trace_id.scope(), trace_event_trace_id.raw_id(),         \
237           v8::internal::tracing::kNoId, trace_event_flags, ##__VA_ARGS__);     \
238     }                                                                          \
239   } while (false)
240 
241 // Adds a trace event with a given timestamp.
242 #define INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP(phase, category_group, name, \
243                                                 timestamp, flags, ...)       \
244   do {                                                                       \
245     INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group);                  \
246     if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) {  \
247       v8::internal::tracing::AddTraceEventWithTimestamp(                     \
248           phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), name,     \
249           v8::internal::tracing::kGlobalScope, v8::internal::tracing::kNoId, \
250           v8::internal::tracing::kNoId, flags, timestamp, ##__VA_ARGS__);    \
251     }                                                                        \
252   } while (false)
253 
254 // Adds a trace event with a given id and timestamp.
255 #define INTERNAL_TRACE_EVENT_ADD_WITH_ID_AND_TIMESTAMP(                        \
256     phase, category_group, name, id, timestamp, flags, ...)                    \
257   do {                                                                         \
258     INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group);                    \
259     if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) {    \
260       unsigned int trace_event_flags = flags | TRACE_EVENT_FLAG_HAS_ID;        \
261       v8::internal::tracing::TraceID trace_event_trace_id(id,                  \
262                                                           &trace_event_flags); \
263       v8::internal::tracing::AddTraceEventWithTimestamp(                       \
264           phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), name,       \
265           trace_event_trace_id.scope(), trace_event_trace_id.raw_id(),         \
266           v8::internal::tracing::kNoId, trace_event_flags, timestamp,          \
267           ##__VA_ARGS__);                                                      \
268     }                                                                          \
269   } while (false)
270 
271 // Adds a trace event with a given id, thread_id, and timestamp. This redirects
272 // to INTERNAL_TRACE_EVENT_ADD_WITH_ID_AND_TIMESTAMP as we presently do not care
273 // about the thread id.
274 #define INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(            \
275     phase, category_group, name, id, thread_id, timestamp, flags, ...) \
276   INTERNAL_TRACE_EVENT_ADD_WITH_ID_AND_TIMESTAMP(                      \
277       phase, category_group, name, id, timestamp, flags, ##__VA_ARGS__)
278 
279 #define TRACE_EVENT_CALL_STATS_SCOPED(isolate, category_group, name) \
280   INTERNAL_TRACE_EVENT_CALL_STATS_SCOPED(isolate, category_group, name)
281 
282 #ifdef V8_RUNTIME_CALL_STATS
283 #define INTERNAL_TRACE_EVENT_CALL_STATS_SCOPED(isolate, category_group, name)  \
284   INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group);                      \
285   v8::internal::tracing::CallStatsScopedTracer INTERNAL_TRACE_EVENT_UID(       \
286       tracer);                                                                 \
287   if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) {      \
288     INTERNAL_TRACE_EVENT_UID(tracer)                                           \
289         .Initialize(isolate, INTERNAL_TRACE_EVENT_UID(category_group_enabled), \
290                     name);                                                     \
291   }
292 #else  // V8_RUNTIME_CALL_STATS
293 #define INTERNAL_TRACE_EVENT_CALL_STATS_SCOPED(isolate, category_group, name)
294 #endif  // V8_RUNTIME_CALL_STATS
295 
296 namespace v8 {
297 namespace internal {
298 
299 class Isolate;
300 
301 namespace tracing {
302 
303 // Specify these values when the corresponding argument of AddTraceEvent
304 // is not used.
305 const int kZeroNumArgs = 0;
306 const decltype(nullptr) kGlobalScope = nullptr;
307 const uint64_t kNoId = 0;
308 
309 class TraceEventHelper {
310  public:
311   V8_EXPORT_PRIVATE static v8::TracingController* GetTracingController();
312 };
313 
314 // TraceID encapsulates an ID that can either be an integer or pointer.
315 class TraceID {
316  public:
317   class WithScope {
318    public:
WithScope(const char * scope,uint64_t raw_id)319     WithScope(const char* scope, uint64_t raw_id)
320         : scope_(scope), raw_id_(raw_id) {}
raw_id()321     uint64_t raw_id() const { return raw_id_; }
scope()322     const char* scope() const { return scope_; }
323 
324    private:
325     const char* scope_ = nullptr;
326     uint64_t raw_id_;
327   };
328 
TraceID(const void * raw_id,unsigned int * flags)329   TraceID(const void* raw_id, unsigned int* flags)
330       : raw_id_(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(raw_id))) {}
TraceID(uint64_t raw_id,unsigned int * flags)331   TraceID(uint64_t raw_id, unsigned int* flags) : raw_id_(raw_id) {
332     (void)flags;
333   }
TraceID(unsigned int raw_id,unsigned int * flags)334   TraceID(unsigned int raw_id, unsigned int* flags) : raw_id_(raw_id) {
335     (void)flags;
336   }
TraceID(uint16_t raw_id,unsigned int * flags)337   TraceID(uint16_t raw_id, unsigned int* flags) : raw_id_(raw_id) {
338     (void)flags;
339   }
TraceID(unsigned char raw_id,unsigned int * flags)340   TraceID(unsigned char raw_id, unsigned int* flags) : raw_id_(raw_id) {
341     (void)flags;
342   }
TraceID(int64_t raw_id,unsigned int * flags)343   TraceID(int64_t raw_id, unsigned int* flags)
344       : raw_id_(static_cast<uint64_t>(raw_id)) {
345     (void)flags;
346   }
TraceID(int raw_id,unsigned int * flags)347   TraceID(int raw_id, unsigned int* flags)
348       : raw_id_(static_cast<uint64_t>(raw_id)) {
349     (void)flags;
350   }
TraceID(int16_t raw_id,unsigned int * flags)351   TraceID(int16_t raw_id, unsigned int* flags)
352       : raw_id_(static_cast<uint64_t>(raw_id)) {
353     (void)flags;
354   }
TraceID(signed char raw_id,unsigned int * flags)355   TraceID(signed char raw_id, unsigned int* flags)
356       : raw_id_(static_cast<uint64_t>(raw_id)) {
357     (void)flags;
358   }
TraceID(WithScope scoped_id,unsigned int * flags)359   TraceID(WithScope scoped_id, unsigned int* flags)
360       : scope_(scoped_id.scope()), raw_id_(scoped_id.raw_id()) {}
361 
raw_id()362   uint64_t raw_id() const { return raw_id_; }
scope()363   const char* scope() const { return scope_; }
364 
365  private:
366   const char* scope_ = nullptr;
367   uint64_t raw_id_;
368 };
369 
370 // Simple container for const char* that should be copied instead of retained.
371 class TraceStringWithCopy {
372  public:
TraceStringWithCopy(const char * str)373   explicit TraceStringWithCopy(const char* str) : str_(str) {}
374   operator const char*() const { return str_; }
375 
376  private:
377   const char* str_;
378 };
379 
AddTraceEventImpl(char phase,const uint8_t * category_group_enabled,const char * name,const char * scope,uint64_t id,uint64_t bind_id,int32_t num_args,const char ** arg_names,const uint8_t * arg_types,const uint64_t * arg_values,unsigned int flags)380 static V8_INLINE uint64_t AddTraceEventImpl(
381     char phase, const uint8_t* category_group_enabled, const char* name,
382     const char* scope, uint64_t id, uint64_t bind_id, int32_t num_args,
383     const char** arg_names, const uint8_t* arg_types,
384     const uint64_t* arg_values, unsigned int flags) {
385   std::unique_ptr<ConvertableToTraceFormat> arg_convertables[2];
386   if (num_args > 0 && arg_types[0] == TRACE_VALUE_TYPE_CONVERTABLE) {
387     arg_convertables[0].reset(reinterpret_cast<ConvertableToTraceFormat*>(
388         static_cast<intptr_t>(arg_values[0])));
389   }
390   if (num_args > 1 && arg_types[1] == TRACE_VALUE_TYPE_CONVERTABLE) {
391     arg_convertables[1].reset(reinterpret_cast<ConvertableToTraceFormat*>(
392         static_cast<intptr_t>(arg_values[1])));
393   }
394   DCHECK_LE(num_args, 2);
395   v8::TracingController* controller =
396       v8::internal::tracing::TraceEventHelper::GetTracingController();
397   return controller->AddTraceEvent(phase, category_group_enabled, name, scope,
398                                    id, bind_id, num_args, arg_names, arg_types,
399                                    arg_values, arg_convertables, flags);
400 }
401 
AddTraceEventWithTimestampImpl(char phase,const uint8_t * category_group_enabled,const char * name,const char * scope,uint64_t id,uint64_t bind_id,int32_t num_args,const char ** arg_names,const uint8_t * arg_types,const uint64_t * arg_values,unsigned int flags,int64_t timestamp)402 static V8_INLINE uint64_t AddTraceEventWithTimestampImpl(
403     char phase, const uint8_t* category_group_enabled, const char* name,
404     const char* scope, uint64_t id, uint64_t bind_id, int32_t num_args,
405     const char** arg_names, const uint8_t* arg_types,
406     const uint64_t* arg_values, unsigned int flags, int64_t timestamp) {
407   std::unique_ptr<ConvertableToTraceFormat> arg_convertables[2];
408   if (num_args > 0 && arg_types[0] == TRACE_VALUE_TYPE_CONVERTABLE) {
409     arg_convertables[0].reset(reinterpret_cast<ConvertableToTraceFormat*>(
410         static_cast<intptr_t>(arg_values[0])));
411   }
412   if (num_args > 1 && arg_types[1] == TRACE_VALUE_TYPE_CONVERTABLE) {
413     arg_convertables[1].reset(reinterpret_cast<ConvertableToTraceFormat*>(
414         static_cast<intptr_t>(arg_values[1])));
415   }
416   DCHECK_LE(num_args, 2);
417   v8::TracingController* controller =
418       v8::internal::tracing::TraceEventHelper::GetTracingController();
419   return controller->AddTraceEventWithTimestamp(
420       phase, category_group_enabled, name, scope, id, bind_id, num_args,
421       arg_names, arg_types, arg_values, arg_convertables, flags, timestamp);
422 }
423 
424 // Define SetTraceValue for each allowed type. It stores the type and
425 // value in the return arguments. This allows this API to avoid declaring any
426 // structures so that it is portable to third_party libraries.
427 // This is the base implementation for integer types (including bool) and enums.
428 template <typename T>
429 static V8_INLINE typename std::enable_if<
430     std::is_integral<T>::value || std::is_enum<T>::value, void>::type
SetTraceValue(T arg,unsigned char * type,uint64_t * value)431 SetTraceValue(T arg, unsigned char* type, uint64_t* value) {
432   *type = std::is_same<T, bool>::value
433               ? TRACE_VALUE_TYPE_BOOL
434               : std::is_signed<T>::value ? TRACE_VALUE_TYPE_INT
435                                          : TRACE_VALUE_TYPE_UINT;
436   *value = static_cast<uint64_t>(arg);
437 }
438 
439 #define INTERNAL_DECLARE_SET_TRACE_VALUE(actual_type, value_type_id)        \
440   static V8_INLINE void SetTraceValue(actual_type arg, unsigned char* type, \
441                                       uint64_t* value) {                    \
442     *type = value_type_id;                                                  \
443     *value = 0;                                                             \
444     STATIC_ASSERT(sizeof(arg) <= sizeof(*value));                           \
445     memcpy(value, &arg, sizeof(arg));                                       \
446   }
INTERNAL_DECLARE_SET_TRACE_VALUE(double,TRACE_VALUE_TYPE_DOUBLE)447 INTERNAL_DECLARE_SET_TRACE_VALUE(double, TRACE_VALUE_TYPE_DOUBLE)
448 INTERNAL_DECLARE_SET_TRACE_VALUE(const void*, TRACE_VALUE_TYPE_POINTER)
449 INTERNAL_DECLARE_SET_TRACE_VALUE(const char*, TRACE_VALUE_TYPE_STRING)
450 INTERNAL_DECLARE_SET_TRACE_VALUE(const TraceStringWithCopy&,
451                                  TRACE_VALUE_TYPE_COPY_STRING)
452 #undef INTERNAL_DECLARE_SET_TRACE_VALUE
453 
454 static V8_INLINE void SetTraceValue(ConvertableToTraceFormat* convertable_value,
455                                     unsigned char* type, uint64_t* value) {
456   *type = TRACE_VALUE_TYPE_CONVERTABLE;
457   *value = static_cast<uint64_t>(reinterpret_cast<intptr_t>(convertable_value));
458 }
459 
460 template <typename T>
461 static V8_INLINE typename std::enable_if<
462     std::is_convertible<T*, ConvertableToTraceFormat*>::value>::type
SetTraceValue(std::unique_ptr<T> ptr,unsigned char * type,uint64_t * value)463 SetTraceValue(std::unique_ptr<T> ptr, unsigned char* type, uint64_t* value) {
464   SetTraceValue(ptr.release(), type, value);
465 }
466 
467 // These AddTraceEvent template
468 // function is defined here instead of in the macro, because the arg_values
469 // could be temporary objects, such as std::string. In order to store
470 // pointers to the internal c_str and pass through to the tracing API,
471 // the arg_values must live throughout these procedures.
472 
AddTraceEvent(char phase,const uint8_t * category_group_enabled,const char * name,const char * scope,uint64_t id,uint64_t bind_id,unsigned int flags)473 static V8_INLINE uint64_t AddTraceEvent(char phase,
474                                         const uint8_t* category_group_enabled,
475                                         const char* name, const char* scope,
476                                         uint64_t id, uint64_t bind_id,
477                                         unsigned int flags) {
478   return TRACE_EVENT_API_ADD_TRACE_EVENT(phase, category_group_enabled, name,
479                                          scope, id, bind_id, kZeroNumArgs,
480                                          nullptr, nullptr, nullptr, flags);
481 }
482 
483 template <class ARG1_TYPE>
AddTraceEvent(char phase,const uint8_t * category_group_enabled,const char * name,const char * scope,uint64_t id,uint64_t bind_id,unsigned int flags,const char * arg1_name,ARG1_TYPE && arg1_val)484 static V8_INLINE uint64_t AddTraceEvent(
485     char phase, const uint8_t* category_group_enabled, const char* name,
486     const char* scope, uint64_t id, uint64_t bind_id, unsigned int flags,
487     const char* arg1_name, ARG1_TYPE&& arg1_val) {
488   const int num_args = 1;
489   uint8_t arg_type;
490   uint64_t arg_value;
491   SetTraceValue(std::forward<ARG1_TYPE>(arg1_val), &arg_type, &arg_value);
492   return TRACE_EVENT_API_ADD_TRACE_EVENT(
493       phase, category_group_enabled, name, scope, id, bind_id, num_args,
494       &arg1_name, &arg_type, &arg_value, flags);
495 }
496 
497 template <class ARG1_TYPE, class ARG2_TYPE>
AddTraceEvent(char phase,const uint8_t * category_group_enabled,const char * name,const char * scope,uint64_t id,uint64_t bind_id,unsigned int flags,const char * arg1_name,ARG1_TYPE && arg1_val,const char * arg2_name,ARG2_TYPE && arg2_val)498 static V8_INLINE uint64_t AddTraceEvent(
499     char phase, const uint8_t* category_group_enabled, const char* name,
500     const char* scope, uint64_t id, uint64_t bind_id, unsigned int flags,
501     const char* arg1_name, ARG1_TYPE&& arg1_val, const char* arg2_name,
502     ARG2_TYPE&& arg2_val) {
503   const int num_args = 2;
504   const char* arg_names[2] = {arg1_name, arg2_name};
505   unsigned char arg_types[2];
506   uint64_t arg_values[2];
507   SetTraceValue(std::forward<ARG1_TYPE>(arg1_val), &arg_types[0],
508                 &arg_values[0]);
509   SetTraceValue(std::forward<ARG2_TYPE>(arg2_val), &arg_types[1],
510                 &arg_values[1]);
511   return TRACE_EVENT_API_ADD_TRACE_EVENT(
512       phase, category_group_enabled, name, scope, id, bind_id, num_args,
513       arg_names, arg_types, arg_values, flags);
514 }
515 
AddTraceEventWithTimestamp(char phase,const uint8_t * category_group_enabled,const char * name,const char * scope,uint64_t id,uint64_t bind_id,unsigned int flags,int64_t timestamp)516 static V8_INLINE uint64_t AddTraceEventWithTimestamp(
517     char phase, const uint8_t* category_group_enabled, const char* name,
518     const char* scope, uint64_t id, uint64_t bind_id, unsigned int flags,
519     int64_t timestamp) {
520   return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_TIMESTAMP(
521       phase, category_group_enabled, name, scope, id, bind_id, kZeroNumArgs,
522       nullptr, nullptr, nullptr, flags, timestamp);
523 }
524 
525 template <class ARG1_TYPE>
AddTraceEventWithTimestamp(char phase,const uint8_t * category_group_enabled,const char * name,const char * scope,uint64_t id,uint64_t bind_id,unsigned int flags,int64_t timestamp,const char * arg1_name,ARG1_TYPE && arg1_val)526 static V8_INLINE uint64_t AddTraceEventWithTimestamp(
527     char phase, const uint8_t* category_group_enabled, const char* name,
528     const char* scope, uint64_t id, uint64_t bind_id, unsigned int flags,
529     int64_t timestamp, const char* arg1_name, ARG1_TYPE&& arg1_val) {
530   const int num_args = 1;
531   uint8_t arg_type;
532   uint64_t arg_value;
533   SetTraceValue(std::forward<ARG1_TYPE>(arg1_val), &arg_type, &arg_value);
534   return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_TIMESTAMP(
535       phase, category_group_enabled, name, scope, id, bind_id, num_args,
536       &arg1_name, &arg_type, &arg_value, flags, timestamp);
537 }
538 
539 template <class ARG1_TYPE, class ARG2_TYPE>
AddTraceEventWithTimestamp(char phase,const uint8_t * category_group_enabled,const char * name,const char * scope,uint64_t id,uint64_t bind_id,unsigned int flags,int64_t timestamp,const char * arg1_name,ARG1_TYPE && arg1_val,const char * arg2_name,ARG2_TYPE && arg2_val)540 static V8_INLINE uint64_t AddTraceEventWithTimestamp(
541     char phase, const uint8_t* category_group_enabled, const char* name,
542     const char* scope, uint64_t id, uint64_t bind_id, unsigned int flags,
543     int64_t timestamp, const char* arg1_name, ARG1_TYPE&& arg1_val,
544     const char* arg2_name, ARG2_TYPE&& arg2_val) {
545   const int num_args = 2;
546   const char* arg_names[2] = {arg1_name, arg2_name};
547   unsigned char arg_types[2];
548   uint64_t arg_values[2];
549   SetTraceValue(std::forward<ARG1_TYPE>(arg1_val), &arg_types[0],
550                 &arg_values[0]);
551   SetTraceValue(std::forward<ARG2_TYPE>(arg2_val), &arg_types[1],
552                 &arg_values[1]);
553   return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_TIMESTAMP(
554       phase, category_group_enabled, name, scope, id, bind_id, num_args,
555       arg_names, arg_types, arg_values, flags, timestamp);
556 }
557 
558 // Used by TRACE_EVENTx macros. Do not use directly.
559 class ScopedTracer {
560  public:
561   // Note: members of data_ intentionally left uninitialized. See Initialize.
ScopedTracer()562   ScopedTracer() : p_data_(nullptr) {}
563 
~ScopedTracer()564   ~ScopedTracer() {
565     if (p_data_ && base::Relaxed_Load(reinterpret_cast<const base::Atomic8*>(
566                        data_.category_group_enabled))) {
567       TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(
568           data_.category_group_enabled, data_.name, data_.event_handle);
569     }
570   }
571 
Initialize(const uint8_t * category_group_enabled,const char * name,uint64_t event_handle)572   void Initialize(const uint8_t* category_group_enabled, const char* name,
573                   uint64_t event_handle) {
574     data_.category_group_enabled = category_group_enabled;
575     data_.name = name;
576     data_.event_handle = event_handle;
577     p_data_ = &data_;
578   }
579 
580  private:
581   // This Data struct workaround is to avoid initializing all the members
582   // in Data during construction of this object, since this object is always
583   // constructed, even when tracing is disabled. If the members of Data were
584   // members of this class instead, compiler warnings occur about potential
585   // uninitialized accesses.
586   struct Data {
587     const uint8_t* category_group_enabled;
588     const char* name;
589     uint64_t event_handle;
590   };
591   Data* p_data_;
592   Data data_;
593 };
594 
595 #ifdef V8_RUNTIME_CALL_STATS
596 // Do not use directly.
597 class CallStatsScopedTracer {
598  public:
CallStatsScopedTracer()599   CallStatsScopedTracer() : p_data_(nullptr) {}
~CallStatsScopedTracer()600   ~CallStatsScopedTracer() {
601     if (V8_UNLIKELY(p_data_ && *data_.category_group_enabled)) {
602       AddEndTraceEvent();
603     }
604   }
605 
606   void Initialize(v8::internal::Isolate* isolate,
607                   const uint8_t* category_group_enabled, const char* name);
608 
609  private:
610   void AddEndTraceEvent();
611   struct Data {
612     const uint8_t* category_group_enabled;
613     const char* name;
614     v8::internal::Isolate* isolate;
615   };
616   bool has_parent_scope_;
617   Data* p_data_;
618   Data data_;
619 };
620 #endif  // defined(V8_RUNTIME_CALL_STATS)
621 
622 }  // namespace tracing
623 }  // namespace internal
624 }  // namespace v8
625 
626 #else  // defined(V8_USE_PERFETTO)
627 
628 #ifdef V8_RUNTIME_CALL_STATS
629 
630 #define TRACE_EVENT_CALL_STATS_SCOPED(isolate, category, name)             \
631   struct PERFETTO_UID(ScopedEvent) {                                       \
632     struct ScopedStats {                                                   \
633       ScopedStats(v8::internal::Isolate* isolate_arg, int) {               \
634         TRACE_EVENT_BEGIN(category, name, [&](perfetto::EventContext) {    \
635           isolate_ = isolate_arg;                                          \
636           internal::RuntimeCallStats* table =                              \
637               isolate_->counters()->runtime_call_stats();                  \
638           has_parent_scope_ = table->InUse();                              \
639           if (!has_parent_scope_) table->Reset();                          \
640         });                                                                \
641       }                                                                    \
642       ~ScopedStats() {                                                     \
643         TRACE_EVENT_END(category, [&](perfetto::EventContext ctx) {        \
644           if (!has_parent_scope_ && isolate_) {                            \
645             /* TODO(skyostil): Write as typed event instead of JSON */     \
646             auto value = v8::tracing::TracedValue::Create();               \
647             isolate_->counters()->runtime_call_stats()->Dump(value.get()); \
648             auto annotation = ctx.event()->add_debug_annotations();        \
649             annotation->set_name("runtime-call-stats");                    \
650             value->Add(annotation);                                        \
651           }                                                                \
652         });                                                                \
653       }                                                                    \
654       v8::internal::Isolate* isolate_;                                     \
655       bool has_parent_scope_;                                              \
656     } stats;                                                               \
657   } PERFETTO_UID(scoped_event) {                                           \
658     { isolate, 0 }                                                         \
659   }
660 
661 #endif  // defined(V8_RUNTIME_CALL_STATS)
662 #endif  // defined(V8_USE_PERFETTO)
663 
664 #endif  // V8_TRACING_TRACE_EVENT_H_
665