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