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 SRC_TRACING_TRACE_EVENT_H_
6 #define SRC_TRACING_TRACE_EVENT_H_
7 
8 #include <stddef.h>
9 
10 #include "base/trace_event/common/trace_event_common.h"
11 #include "include/v8-platform.h"
12 #include "src/base/atomicops.h"
13 
14 // This header file defines implementation details of how the trace macros in
15 // trace_event_common.h collect and store trace events. Anything not
16 // implementation-specific should go in trace_macros_common.h instead of here.
17 
18 
19 // The pointer returned from GetCategoryGroupEnabled() points to a
20 // value with zero or more of the following bits. Used in this class only.
21 // The TRACE_EVENT macros should only use the value as a bool.
22 // These values must be in sync with macro values in trace_log.h in
23 // chromium.
24 enum CategoryGroupEnabledFlags {
25   // Category group enabled for the recording mode.
26   kEnabledForRecording_CategoryGroupEnabledFlags = 1 << 0,
27   // Category group enabled for the monitoring mode.
28   kEnabledForMonitoring_CategoryGroupEnabledFlags = 1 << 1,
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 // Sets the current sample state to the given category and name (both must be
48 // constant strings). These states are intended for a sampling profiler.
49 // Implementation note: we store category and name together because we don't
50 // want the inconsistency/expense of storing two pointers.
51 // |thread_bucket| is [0..2] and is used to statically isolate samples in one
52 // thread from others.
53 #define TRACE_EVENT_SET_SAMPLING_STATE_FOR_BUCKET(bucket_number, category, \
54                                                   name)                    \
55   v8::internal::tracing::TraceEventSamplingStateScope<bucket_number>::Set( \
56       category "\0" name)
57 
58 // Returns a current sampling state of the given bucket.
59 #define TRACE_EVENT_GET_SAMPLING_STATE_FOR_BUCKET(bucket_number) \
60   v8::internal::tracing::TraceEventSamplingStateScope<bucket_number>::Current()
61 
62 // Creates a scope of a sampling state of the given bucket.
63 //
64 // {  // The sampling state is set within this scope.
65 //    TRACE_EVENT_SAMPLING_STATE_SCOPE_FOR_BUCKET(0, "category", "name");
66 //    ...;
67 // }
68 #define TRACE_EVENT_SCOPED_SAMPLING_STATE_FOR_BUCKET(bucket_number, category, \
69                                                      name)                    \
70   v8::internal::TraceEventSamplingStateScope<bucket_number>                   \
71       traceEventSamplingScope(category "\0" name);
72 
73 
74 #define INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE() \
75   *INTERNAL_TRACE_EVENT_UID(category_group_enabled) &                    \
76       (kEnabledForRecording_CategoryGroupEnabledFlags |                  \
77        kEnabledForEventCallback_CategoryGroupEnabledFlags)
78 
79 // The following macro has no implementation, but it needs to exist since
80 // it gets called from scoped trace events. It cannot call UNIMPLEMENTED()
81 // since an empty implementation is a valid one.
82 #define INTERNAL_TRACE_MEMORY(category, name)
83 
84 ////////////////////////////////////////////////////////////////////////////////
85 // Implementation specific tracing API definitions.
86 
87 // Get a pointer to the enabled state of the given trace category. Only
88 // long-lived literal strings should be given as the category group. The
89 // returned pointer can be held permanently in a local static for example. If
90 // the unsigned char is non-zero, tracing is enabled. If tracing is enabled,
91 // TRACE_EVENT_API_ADD_TRACE_EVENT can be called. It's OK if tracing is disabled
92 // between the load of the tracing state and the call to
93 // TRACE_EVENT_API_ADD_TRACE_EVENT, because this flag only provides an early out
94 // for best performance when tracing is disabled.
95 // const uint8_t*
96 //     TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(const char* category_group)
97 #define TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED              \
98   v8::internal::tracing::TraceEventHelper::GetCurrentPlatform() \
99       ->GetCategoryGroupEnabled
100 
101 // Get the number of times traces have been recorded. This is used to implement
102 // the TRACE_EVENT_IS_NEW_TRACE facility.
103 // unsigned int TRACE_EVENT_API_GET_NUM_TRACES_RECORDED()
104 #define TRACE_EVENT_API_GET_NUM_TRACES_RECORDED                 \
105   v8::internal::tracing::TraceEventHelper::GetCurrentPlatform() \
106       ->getNumTracesRecorded
107 
108 // Add a trace event to the platform tracing system.
109 // uint64_t TRACE_EVENT_API_ADD_TRACE_EVENT(
110 //                    char phase,
111 //                    const uint8_t* category_group_enabled,
112 //                    const char* name,
113 //                    uint64_t id,
114 //                    uint64_t bind_id,
115 //                    int num_args,
116 //                    const char** arg_names,
117 //                    const uint8_t* arg_types,
118 //                    const uint64_t* arg_values,
119 //                    unsigned int flags)
120 #define TRACE_EVENT_API_ADD_TRACE_EVENT \
121   v8::internal::tracing::TraceEventHelper::GetCurrentPlatform()->AddTraceEvent
122 
123 // Set the duration field of a COMPLETE trace event.
124 // void TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(
125 //     const uint8_t* category_group_enabled,
126 //     const char* name,
127 //     uint64_t id)
128 #define TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION             \
129   v8::internal::tracing::TraceEventHelper::GetCurrentPlatform() \
130       ->UpdateTraceEventDuration
131 
132 // Defines atomic operations used internally by the tracing system.
133 #define TRACE_EVENT_API_ATOMIC_WORD v8::base::AtomicWord
134 #define TRACE_EVENT_API_ATOMIC_LOAD(var) v8::base::NoBarrier_Load(&(var))
135 #define TRACE_EVENT_API_ATOMIC_STORE(var, value) \
136   v8::base::NoBarrier_Store(&(var), (value))
137 
138 // The thread buckets for the sampling profiler.
139 extern TRACE_EVENT_API_ATOMIC_WORD g_trace_state[3];
140 
141 #define TRACE_EVENT_API_THREAD_BUCKET(thread_bucket) \
142   g_trace_state[thread_bucket]
143 
144 ////////////////////////////////////////////////////////////////////////////////
145 
146 // Implementation detail: trace event macros create temporary variables
147 // to keep instrumentation overhead low. These macros give each temporary
148 // variable a unique name based on the line number to prevent name collisions.
149 #define INTERNAL_TRACE_EVENT_UID3(a, b) trace_event_unique_##a##b
150 #define INTERNAL_TRACE_EVENT_UID2(a, b) INTERNAL_TRACE_EVENT_UID3(a, b)
151 #define INTERNAL_TRACE_EVENT_UID(name_prefix) \
152   INTERNAL_TRACE_EVENT_UID2(name_prefix, __LINE__)
153 
154 // Implementation detail: internal macro to create static category.
155 // No barriers are needed, because this code is designed to operate safely
156 // even when the unsigned char* points to garbage data (which may be the case
157 // on processors without cache coherency).
158 // TODO(fmeawad): This implementation contradicts that we can have a different
159 // configuration for each isolate,
160 // https://code.google.com/p/v8/issues/detail?id=4563
161 #define INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO_CUSTOM_VARIABLES(             \
162     category_group, atomic, category_group_enabled)                          \
163   category_group_enabled =                                                   \
164       reinterpret_cast<const uint8_t*>(TRACE_EVENT_API_ATOMIC_LOAD(atomic)); \
165   if (!category_group_enabled) {                                             \
166     category_group_enabled =                                                 \
167         TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(category_group);          \
168     TRACE_EVENT_API_ATOMIC_STORE(                                            \
169         atomic, reinterpret_cast<TRACE_EVENT_API_ATOMIC_WORD>(               \
170                     category_group_enabled));                                \
171   }
172 
173 #define INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group)             \
174   static TRACE_EVENT_API_ATOMIC_WORD INTERNAL_TRACE_EVENT_UID(atomic) = 0; \
175   const uint8_t* INTERNAL_TRACE_EVENT_UID(category_group_enabled);         \
176   INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO_CUSTOM_VARIABLES(                 \
177       category_group, INTERNAL_TRACE_EVENT_UID(atomic),                    \
178       INTERNAL_TRACE_EVENT_UID(category_group_enabled));
179 
180 // Implementation detail: internal macro to create static category and add
181 // event if the category is enabled.
182 #define INTERNAL_TRACE_EVENT_ADD(phase, category_group, name, flags, ...)    \
183   do {                                                                       \
184     INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group);                  \
185     if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) {  \
186       v8::internal::tracing::AddTraceEvent(                                  \
187           phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), name,     \
188           v8::internal::tracing::kNoId, v8::internal::tracing::kNoId, flags, \
189           ##__VA_ARGS__);                                                    \
190     }                                                                        \
191   } while (0)
192 
193 // Implementation detail: internal macro to create static category and add begin
194 // event if the category is enabled. Also adds the end event when the scope
195 // ends.
196 #define INTERNAL_TRACE_EVENT_ADD_SCOPED(category_group, name, ...)          \
197   INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group);                   \
198   v8::internal::tracing::ScopedTracer INTERNAL_TRACE_EVENT_UID(tracer);     \
199   if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) {   \
200     uint64_t h = v8::internal::tracing::AddTraceEvent(                      \
201         TRACE_EVENT_PHASE_COMPLETE,                                         \
202         INTERNAL_TRACE_EVENT_UID(category_group_enabled), name,             \
203         v8::internal::tracing::kNoId, v8::internal::tracing::kNoId,         \
204         TRACE_EVENT_FLAG_NONE, ##__VA_ARGS__);                              \
205     INTERNAL_TRACE_EVENT_UID(tracer)                                        \
206         .Initialize(INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, \
207                     h);                                                     \
208   }
209 
210 #define INTERNAL_TRACE_EVENT_ADD_SCOPED_WITH_FLOW(category_group, name,     \
211                                                   bind_id, flow_flags, ...) \
212   INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group);                   \
213   v8::internal::tracing::ScopedTracer INTERNAL_TRACE_EVENT_UID(tracer);     \
214   if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) {   \
215     unsigned int trace_event_flags = flow_flags;                            \
216     v8::internal::tracing::TraceID trace_event_bind_id(bind_id,             \
217                                                        &trace_event_flags); \
218     uint64_t h = v8::internal::tracing::AddTraceEvent(                      \
219         TRACE_EVENT_PHASE_COMPLETE,                                         \
220         INTERNAL_TRACE_EVENT_UID(category_group_enabled), name,             \
221         v8::internal::tracing::kNoId, trace_event_bind_id.data(),           \
222         trace_event_flags, ##__VA_ARGS__);                                  \
223     INTERNAL_TRACE_EVENT_UID(tracer)                                        \
224         .Initialize(INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, \
225                     h);                                                     \
226   }
227 
228 // Implementation detail: internal macro to create static category and add
229 // event if the category is enabled.
230 #define INTERNAL_TRACE_EVENT_ADD_WITH_ID(phase, category_group, name, id,      \
231                                          flags, ...)                           \
232   do {                                                                         \
233     INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group);                    \
234     if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) {    \
235       unsigned int trace_event_flags = flags | TRACE_EVENT_FLAG_HAS_ID;        \
236       v8::internal::tracing::TraceID trace_event_trace_id(id,                  \
237                                                           &trace_event_flags); \
238       v8::internal::tracing::AddTraceEvent(                                    \
239           phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), name,       \
240           trace_event_trace_id.data(), v8::internal::tracing::kNoId,           \
241           trace_event_flags, ##__VA_ARGS__);                                   \
242     }                                                                          \
243   } while (0)
244 
245 // Adds a trace event with a given timestamp. Not Implemented.
246 #define INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP(phase, category_group, name, \
247                                                 timestamp, flags, ...)       \
248   UNIMPLEMENTED()
249 
250 // Adds a trace event with a given id and timestamp. Not Implemented.
251 #define INTERNAL_TRACE_EVENT_ADD_WITH_ID_AND_TIMESTAMP(     \
252     phase, category_group, name, id, timestamp, flags, ...) \
253   UNIMPLEMENTED()
254 
255 // Adds a trace event with a given id, thread_id, and timestamp. Not
256 // Implemented.
257 #define INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(            \
258     phase, category_group, name, id, thread_id, timestamp, flags, ...) \
259   UNIMPLEMENTED()
260 
261 namespace v8 {
262 namespace internal {
263 namespace tracing {
264 
265 // Specify these values when the corresponding argument of AddTraceEvent is not
266 // used.
267 const int kZeroNumArgs = 0;
268 const uint64_t kNoId = 0;
269 
270 class TraceEventHelper {
271  public:
272   static v8::Platform* GetCurrentPlatform();
273 };
274 
275 // TraceID encapsulates an ID that can either be an integer or pointer. Pointers
276 // are by default mangled with the Process ID so that they are unlikely to
277 // collide when the same pointer is used on different processes.
278 class TraceID {
279  public:
280   class DontMangle {
281    public:
DontMangle(const void * id)282     explicit DontMangle(const void* id)
283         : data_(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(id))) {}
DontMangle(uint64_t id)284     explicit DontMangle(uint64_t id) : data_(id) {}
DontMangle(unsigned int id)285     explicit DontMangle(unsigned int id) : data_(id) {}
DontMangle(uint16_t id)286     explicit DontMangle(uint16_t id) : data_(id) {}
DontMangle(unsigned char id)287     explicit DontMangle(unsigned char id) : data_(id) {}
DontMangle(int64_t id)288     explicit DontMangle(int64_t id) : data_(static_cast<uint64_t>(id)) {}
DontMangle(int id)289     explicit DontMangle(int id) : data_(static_cast<uint64_t>(id)) {}
DontMangle(int16_t id)290     explicit DontMangle(int16_t id) : data_(static_cast<uint64_t>(id)) {}
DontMangle(signed char id)291     explicit DontMangle(signed char id) : data_(static_cast<uint64_t>(id)) {}
data()292     uint64_t data() const { return data_; }
293 
294    private:
295     uint64_t data_;
296   };
297 
298   class ForceMangle {
299    public:
ForceMangle(uint64_t id)300     explicit ForceMangle(uint64_t id) : data_(id) {}
ForceMangle(unsigned int id)301     explicit ForceMangle(unsigned int id) : data_(id) {}
ForceMangle(uint16_t id)302     explicit ForceMangle(uint16_t id) : data_(id) {}
ForceMangle(unsigned char id)303     explicit ForceMangle(unsigned char id) : data_(id) {}
ForceMangle(int64_t id)304     explicit ForceMangle(int64_t id) : data_(static_cast<uint64_t>(id)) {}
ForceMangle(int id)305     explicit ForceMangle(int id) : data_(static_cast<uint64_t>(id)) {}
ForceMangle(int16_t id)306     explicit ForceMangle(int16_t id) : data_(static_cast<uint64_t>(id)) {}
ForceMangle(signed char id)307     explicit ForceMangle(signed char id) : data_(static_cast<uint64_t>(id)) {}
data()308     uint64_t data() const { return data_; }
309 
310    private:
311     uint64_t data_;
312   };
313 
TraceID(const void * id,unsigned int * flags)314   TraceID(const void* id, unsigned int* flags)
315       : data_(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(id))) {
316     *flags |= TRACE_EVENT_FLAG_MANGLE_ID;
317   }
TraceID(ForceMangle id,unsigned int * flags)318   TraceID(ForceMangle id, unsigned int* flags) : data_(id.data()) {
319     *flags |= TRACE_EVENT_FLAG_MANGLE_ID;
320   }
TraceID(DontMangle id,unsigned int * flags)321   TraceID(DontMangle id, unsigned int* flags) : data_(id.data()) {}
TraceID(uint64_t id,unsigned int * flags)322   TraceID(uint64_t id, unsigned int* flags) : data_(id) { (void)flags; }
TraceID(unsigned int id,unsigned int * flags)323   TraceID(unsigned int id, unsigned int* flags) : data_(id) { (void)flags; }
TraceID(uint16_t id,unsigned int * flags)324   TraceID(uint16_t id, unsigned int* flags) : data_(id) { (void)flags; }
TraceID(unsigned char id,unsigned int * flags)325   TraceID(unsigned char id, unsigned int* flags) : data_(id) { (void)flags; }
TraceID(int64_t id,unsigned int * flags)326   TraceID(int64_t id, unsigned int* flags) : data_(static_cast<uint64_t>(id)) {
327     (void)flags;
328   }
TraceID(int id,unsigned int * flags)329   TraceID(int id, unsigned int* flags) : data_(static_cast<uint64_t>(id)) {
330     (void)flags;
331   }
TraceID(int16_t id,unsigned int * flags)332   TraceID(int16_t id, unsigned int* flags) : data_(static_cast<uint64_t>(id)) {
333     (void)flags;
334   }
TraceID(signed char id,unsigned int * flags)335   TraceID(signed char id, unsigned int* flags)
336       : data_(static_cast<uint64_t>(id)) {
337     (void)flags;
338   }
339 
data()340   uint64_t data() const { return data_; }
341 
342  private:
343   uint64_t data_;
344 };
345 
346 // Simple union to store various types as uint64_t.
347 union TraceValueUnion {
348   bool as_bool;
349   uint64_t as_uint;
350   int64_t as_int;
351   double as_double;
352   const void* as_pointer;
353   const char* as_string;
354 };
355 
356 // Simple container for const char* that should be copied instead of retained.
357 class TraceStringWithCopy {
358  public:
TraceStringWithCopy(const char * str)359   explicit TraceStringWithCopy(const char* str) : str_(str) {}
360   operator const char*() const { return str_; }
361 
362  private:
363   const char* str_;
364 };
365 
366 // Define SetTraceValue for each allowed type. It stores the type and
367 // value in the return arguments. This allows this API to avoid declaring any
368 // structures so that it is portable to third_party libraries.
369 #define INTERNAL_DECLARE_SET_TRACE_VALUE(actual_type, union_member,         \
370                                          value_type_id)                     \
371   static V8_INLINE void SetTraceValue(actual_type arg, unsigned char* type, \
372                                       uint64_t* value) {                    \
373     TraceValueUnion type_value;                                             \
374     type_value.union_member = arg;                                          \
375     *type = value_type_id;                                                  \
376     *value = type_value.as_uint;                                            \
377   }
378 // Simpler form for int types that can be safely casted.
379 #define INTERNAL_DECLARE_SET_TRACE_VALUE_INT(actual_type, value_type_id)    \
380   static V8_INLINE void SetTraceValue(actual_type arg, unsigned char* type, \
381                                       uint64_t* value) {                    \
382     *type = value_type_id;                                                  \
383     *value = static_cast<uint64_t>(arg);                                    \
384   }
385 
INTERNAL_DECLARE_SET_TRACE_VALUE_INT(uint64_t,TRACE_VALUE_TYPE_UINT)386 INTERNAL_DECLARE_SET_TRACE_VALUE_INT(uint64_t, TRACE_VALUE_TYPE_UINT)
387 INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned int, TRACE_VALUE_TYPE_UINT)
388 INTERNAL_DECLARE_SET_TRACE_VALUE_INT(uint16_t, TRACE_VALUE_TYPE_UINT)
389 INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned char, TRACE_VALUE_TYPE_UINT)
390 INTERNAL_DECLARE_SET_TRACE_VALUE_INT(int64_t, TRACE_VALUE_TYPE_INT)
391 INTERNAL_DECLARE_SET_TRACE_VALUE_INT(int, TRACE_VALUE_TYPE_INT)
392 INTERNAL_DECLARE_SET_TRACE_VALUE_INT(int16_t, TRACE_VALUE_TYPE_INT)
393 INTERNAL_DECLARE_SET_TRACE_VALUE_INT(signed char, TRACE_VALUE_TYPE_INT)
394 INTERNAL_DECLARE_SET_TRACE_VALUE(bool, as_bool, TRACE_VALUE_TYPE_BOOL)
395 INTERNAL_DECLARE_SET_TRACE_VALUE(double, as_double, TRACE_VALUE_TYPE_DOUBLE)
396 INTERNAL_DECLARE_SET_TRACE_VALUE(const void*, as_pointer,
397                                  TRACE_VALUE_TYPE_POINTER)
398 INTERNAL_DECLARE_SET_TRACE_VALUE(const char*, as_string,
399                                  TRACE_VALUE_TYPE_STRING)
400 INTERNAL_DECLARE_SET_TRACE_VALUE(const TraceStringWithCopy&, as_string,
401                                  TRACE_VALUE_TYPE_COPY_STRING)
402 
403 #undef INTERNAL_DECLARE_SET_TRACE_VALUE
404 #undef INTERNAL_DECLARE_SET_TRACE_VALUE_INT
405 
406 // These AddTraceEvent template
407 // function is defined here instead of in the macro, because the arg_values
408 // could be temporary objects, such as std::string. In order to store
409 // pointers to the internal c_str and pass through to the tracing API,
410 // the arg_values must live throughout these procedures.
411 
412 static V8_INLINE uint64_t AddTraceEvent(char phase,
413                                         const uint8_t* category_group_enabled,
414                                         const char* name, uint64_t id,
415                                         uint64_t bind_id, unsigned int flags) {
416   return TRACE_EVENT_API_ADD_TRACE_EVENT(phase, category_group_enabled, name,
417                                          id, bind_id, kZeroNumArgs, NULL, NULL,
418                                          NULL, flags);
419 }
420 
421 template <class ARG1_TYPE>
AddTraceEvent(char phase,const uint8_t * category_group_enabled,const char * name,uint64_t id,uint64_t bind_id,unsigned int flags,const char * arg1_name,const ARG1_TYPE & arg1_val)422 static V8_INLINE uint64_t AddTraceEvent(char phase,
423                                         const uint8_t* category_group_enabled,
424                                         const char* name, uint64_t id,
425                                         uint64_t bind_id, unsigned int flags,
426                                         const char* arg1_name,
427                                         const ARG1_TYPE& arg1_val) {
428   const int num_args = 1;
429   uint8_t arg_types[1];
430   uint64_t arg_values[1];
431   SetTraceValue(arg1_val, &arg_types[0], &arg_values[0]);
432   return TRACE_EVENT_API_ADD_TRACE_EVENT(phase, category_group_enabled, name,
433                                          id, bind_id, num_args, &arg1_name,
434                                          arg_types, arg_values, flags);
435 }
436 
437 template <class ARG1_TYPE, class ARG2_TYPE>
AddTraceEvent(char phase,const uint8_t * category_group_enabled,const char * name,uint64_t id,uint64_t bind_id,unsigned int flags,const char * arg1_name,const ARG1_TYPE & arg1_val,const char * arg2_name,const ARG2_TYPE & arg2_val)438 static V8_INLINE uint64_t AddTraceEvent(
439     char phase, const uint8_t* category_group_enabled, const char* name,
440     uint64_t id, uint64_t bind_id, unsigned int flags, const char* arg1_name,
441     const ARG1_TYPE& arg1_val, const char* arg2_name,
442     const ARG2_TYPE& arg2_val) {
443   const int num_args = 2;
444   const char* arg_names[2] = {arg1_name, arg2_name};
445   unsigned char arg_types[2];
446   uint64_t arg_values[2];
447   SetTraceValue(arg1_val, &arg_types[0], &arg_values[0]);
448   SetTraceValue(arg2_val, &arg_types[1], &arg_values[1]);
449   return TRACE_EVENT_API_ADD_TRACE_EVENT(phase, category_group_enabled, name,
450                                          id, bind_id, num_args, arg_names,
451                                          arg_types, arg_values, flags);
452 }
453 
454 // Used by TRACE_EVENTx macros. Do not use directly.
455 class ScopedTracer {
456  public:
457   // Note: members of data_ intentionally left uninitialized. See Initialize.
ScopedTracer()458   ScopedTracer() : p_data_(NULL) {}
459 
~ScopedTracer()460   ~ScopedTracer() {
461     if (p_data_ && *data_.category_group_enabled)
462       TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(
463           data_.category_group_enabled, data_.name, data_.event_handle);
464   }
465 
Initialize(const uint8_t * category_group_enabled,const char * name,uint64_t event_handle)466   void Initialize(const uint8_t* category_group_enabled, const char* name,
467                   uint64_t event_handle) {
468     data_.category_group_enabled = category_group_enabled;
469     data_.name = name;
470     data_.event_handle = event_handle;
471     p_data_ = &data_;
472   }
473 
474  private:
475   // This Data struct workaround is to avoid initializing all the members
476   // in Data during construction of this object, since this object is always
477   // constructed, even when tracing is disabled. If the members of Data were
478   // members of this class instead, compiler warnings occur about potential
479   // uninitialized accesses.
480   struct Data {
481     const uint8_t* category_group_enabled;
482     const char* name;
483     uint64_t event_handle;
484   };
485   Data* p_data_;
486   Data data_;
487 };
488 
489 // Used by TRACE_EVENT_BINARY_EFFICIENTx macro. Do not use directly.
490 class ScopedTraceBinaryEfficient {
491  public:
492   ScopedTraceBinaryEfficient(const char* category_group, const char* name);
493   ~ScopedTraceBinaryEfficient();
494 
495  private:
496   const uint8_t* category_group_enabled_;
497   const char* name_;
498   uint64_t event_handle_;
499 };
500 
501 // TraceEventSamplingStateScope records the current sampling state
502 // and sets a new sampling state. When the scope exists, it restores
503 // the sampling state having recorded.
504 template <size_t BucketNumber>
505 class TraceEventSamplingStateScope {
506  public:
TraceEventSamplingStateScope(const char * category_and_name)507   explicit TraceEventSamplingStateScope(const char* category_and_name) {
508     previous_state_ = TraceEventSamplingStateScope<BucketNumber>::Current();
509     TraceEventSamplingStateScope<BucketNumber>::Set(category_and_name);
510   }
511 
~TraceEventSamplingStateScope()512   ~TraceEventSamplingStateScope() {
513     TraceEventSamplingStateScope<BucketNumber>::Set(previous_state_);
514   }
515 
Current()516   static V8_INLINE const char* Current() {
517     return reinterpret_cast<const char*>(
518         TRACE_EVENT_API_ATOMIC_LOAD(g_trace_state[BucketNumber]));
519   }
520 
Set(const char * category_and_name)521   static V8_INLINE void Set(const char* category_and_name) {
522     TRACE_EVENT_API_ATOMIC_STORE(g_trace_state[BucketNumber],
523                                  reinterpret_cast<TRACE_EVENT_API_ATOMIC_WORD>(
524                                      const_cast<char*>(category_and_name)));
525   }
526 
527  private:
528   const char* previous_state_;
529 };
530 
531 }  // namespace tracing
532 }  // namespace internal
533 }  // namespace v8
534 
535 #endif  // SRC_TRACING_TRACE_EVENT_H_
536