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