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