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