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