1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef SRC_TRACING_TRACE_EVENT_H_
6 #define SRC_TRACING_TRACE_EVENT_H_
7
8 #include <stddef.h>
9 #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::GetCurrentPlatform() \
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 // Set the duration field of a COMPLETE trace event.
100 // void TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(
101 // const uint8_t* category_group_enabled,
102 // const char* name,
103 // uint64_t id)
104 #define TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION \
105 v8::internal::tracing::TraceEventHelper::GetCurrentPlatform() \
106 ->UpdateTraceEventDuration
107
108 // Defines atomic operations used internally by the tracing system.
109 #define TRACE_EVENT_API_ATOMIC_WORD v8::base::AtomicWord
110 #define TRACE_EVENT_API_ATOMIC_LOAD(var) v8::base::NoBarrier_Load(&(var))
111 #define TRACE_EVENT_API_ATOMIC_STORE(var, value) \
112 v8::base::NoBarrier_Store(&(var), (value))
113
114 ////////////////////////////////////////////////////////////////////////////////
115
116 // Implementation detail: trace event macros create temporary variables
117 // to keep instrumentation overhead low. These macros give each temporary
118 // variable a unique name based on the line number to prevent name collisions.
119 #define INTERNAL_TRACE_EVENT_UID3(a, b) trace_event_unique_##a##b
120 #define INTERNAL_TRACE_EVENT_UID2(a, b) INTERNAL_TRACE_EVENT_UID3(a, b)
121 #define INTERNAL_TRACE_EVENT_UID(name_prefix) \
122 INTERNAL_TRACE_EVENT_UID2(name_prefix, __LINE__)
123
124 // Implementation detail: internal macro to create static category.
125 // No barriers are needed, because this code is designed to operate safely
126 // even when the unsigned char* points to garbage data (which may be the case
127 // on processors without cache coherency).
128 // TODO(fmeawad): This implementation contradicts that we can have a different
129 // configuration for each isolate,
130 // https://code.google.com/p/v8/issues/detail?id=4563
131 #define INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO_CUSTOM_VARIABLES( \
132 category_group, atomic, category_group_enabled) \
133 category_group_enabled = \
134 reinterpret_cast<const uint8_t*>(TRACE_EVENT_API_ATOMIC_LOAD(atomic)); \
135 if (!category_group_enabled) { \
136 category_group_enabled = \
137 TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(category_group); \
138 TRACE_EVENT_API_ATOMIC_STORE( \
139 atomic, reinterpret_cast<TRACE_EVENT_API_ATOMIC_WORD>( \
140 category_group_enabled)); \
141 }
142
143 #define INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group) \
144 static TRACE_EVENT_API_ATOMIC_WORD INTERNAL_TRACE_EVENT_UID(atomic) = 0; \
145 const uint8_t* INTERNAL_TRACE_EVENT_UID(category_group_enabled); \
146 INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO_CUSTOM_VARIABLES( \
147 category_group, INTERNAL_TRACE_EVENT_UID(atomic), \
148 INTERNAL_TRACE_EVENT_UID(category_group_enabled));
149
150 // Implementation detail: internal macro to create static category and add
151 // event if the category is enabled.
152 #define INTERNAL_TRACE_EVENT_ADD(phase, category_group, name, flags, ...) \
153 do { \
154 INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
155 if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
156 v8::internal::tracing::AddTraceEvent( \
157 phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, \
158 v8::internal::tracing::kGlobalScope, v8::internal::tracing::kNoId, \
159 v8::internal::tracing::kNoId, flags, ##__VA_ARGS__); \
160 } \
161 } while (0)
162
163 // Implementation detail: internal macro to create static category and add begin
164 // event if the category is enabled. Also adds the end event when the scope
165 // ends.
166 #define INTERNAL_TRACE_EVENT_ADD_SCOPED(category_group, name, ...) \
167 INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
168 v8::internal::tracing::ScopedTracer INTERNAL_TRACE_EVENT_UID(tracer); \
169 if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
170 uint64_t h = v8::internal::tracing::AddTraceEvent( \
171 TRACE_EVENT_PHASE_COMPLETE, \
172 INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, \
173 v8::internal::tracing::kGlobalScope, v8::internal::tracing::kNoId, \
174 v8::internal::tracing::kNoId, TRACE_EVENT_FLAG_NONE, ##__VA_ARGS__); \
175 INTERNAL_TRACE_EVENT_UID(tracer) \
176 .Initialize(INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, \
177 h); \
178 }
179
180 #define INTERNAL_TRACE_EVENT_ADD_SCOPED_WITH_FLOW(category_group, name, \
181 bind_id, flow_flags, ...) \
182 INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
183 v8::internal::tracing::ScopedTracer INTERNAL_TRACE_EVENT_UID(tracer); \
184 if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
185 unsigned int trace_event_flags = flow_flags; \
186 v8::internal::tracing::TraceID trace_event_bind_id(bind_id, \
187 &trace_event_flags); \
188 uint64_t h = v8::internal::tracing::AddTraceEvent( \
189 TRACE_EVENT_PHASE_COMPLETE, \
190 INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, \
191 v8::internal::tracing::kGlobalScope, v8::internal::tracing::kNoId, \
192 trace_event_bind_id.raw_id(), trace_event_flags, ##__VA_ARGS__); \
193 INTERNAL_TRACE_EVENT_UID(tracer) \
194 .Initialize(INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, \
195 h); \
196 }
197
198 // Implementation detail: internal macro to create static category and add
199 // event if the category is enabled.
200 #define INTERNAL_TRACE_EVENT_ADD_WITH_ID(phase, category_group, name, id, \
201 flags, ...) \
202 do { \
203 INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
204 if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
205 unsigned int trace_event_flags = flags | TRACE_EVENT_FLAG_HAS_ID; \
206 v8::internal::tracing::TraceID trace_event_trace_id(id, \
207 &trace_event_flags); \
208 v8::internal::tracing::AddTraceEvent( \
209 phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, \
210 trace_event_trace_id.scope(), trace_event_trace_id.raw_id(), \
211 v8::internal::tracing::kNoId, trace_event_flags, ##__VA_ARGS__); \
212 } \
213 } while (0)
214
215 // Adds a trace event with a given timestamp. Not Implemented.
216 #define INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP(phase, category_group, name, \
217 timestamp, flags, ...) \
218 UNIMPLEMENTED()
219
220 // Adds a trace event with a given id and timestamp. Not Implemented.
221 #define INTERNAL_TRACE_EVENT_ADD_WITH_ID_AND_TIMESTAMP( \
222 phase, category_group, name, id, timestamp, flags, ...) \
223 UNIMPLEMENTED()
224
225 // Adds a trace event with a given id, thread_id, and timestamp. Not
226 // Implemented.
227 #define INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
228 phase, category_group, name, id, thread_id, timestamp, flags, ...) \
229 UNIMPLEMENTED()
230
231 // Enter and leave a context based on the current scope.
232 #define INTERNAL_TRACE_EVENT_SCOPED_CONTEXT(category_group, name, context) \
233 struct INTERNAL_TRACE_EVENT_UID(ScopedContext) { \
234 public: \
235 INTERNAL_TRACE_EVENT_UID(ScopedContext)(uint64_t cid) : cid_(cid) { \
236 TRACE_EVENT_ENTER_CONTEXT(category_group, name, cid_); \
237 } \
238 ~INTERNAL_TRACE_EVENT_UID(ScopedContext)() { \
239 TRACE_EVENT_LEAVE_CONTEXT(category_group, name, cid_); \
240 } \
241 \
242 private: \
243 /* Local class friendly DISALLOW_COPY_AND_ASSIGN */ \
244 INTERNAL_TRACE_EVENT_UID(ScopedContext) \
245 (const INTERNAL_TRACE_EVENT_UID(ScopedContext)&) {} \
246 void operator=(const INTERNAL_TRACE_EVENT_UID(ScopedContext)&) {} \
247 uint64_t cid_; \
248 }; \
249 INTERNAL_TRACE_EVENT_UID(ScopedContext) \
250 INTERNAL_TRACE_EVENT_UID(scoped_context)(context);
251
252 #define TRACE_EVENT_CALL_STATS_SCOPED(isolate, category_group, name) \
253 INTERNAL_TRACE_EVENT_CALL_STATS_SCOPED(isolate, category_group, name)
254
255 #define INTERNAL_TRACE_EVENT_CALL_STATS_SCOPED(isolate, category_group, name) \
256 INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
257 v8::internal::tracing::CallStatsScopedTracer INTERNAL_TRACE_EVENT_UID( \
258 tracer); \
259 if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
260 INTERNAL_TRACE_EVENT_UID(tracer) \
261 .Initialize(isolate, INTERNAL_TRACE_EVENT_UID(category_group_enabled), \
262 name); \
263 }
264
265 namespace v8 {
266 namespace internal {
267
268 class Isolate;
269
270 namespace tracing {
271
272 // Specify these values when the corresponding argument of AddTraceEvent is not
273 // used.
274 const int kZeroNumArgs = 0;
275 const decltype(nullptr) kGlobalScope = nullptr;
276 const uint64_t kNoId = 0;
277
278 extern base::Atomic32 kRuntimeCallStatsTracingEnabled;
279
280 class TraceEventHelper {
281 public:
282 static v8::Platform* GetCurrentPlatform();
283 };
284
285 // TraceID encapsulates an ID that can either be an integer or pointer. Pointers
286 // are by default mangled with the Process ID so that they are unlikely to
287 // collide when the same pointer is used on different processes.
288 class TraceID {
289 public:
290 class WithScope {
291 public:
WithScope(const char * scope,uint64_t raw_id)292 WithScope(const char* scope, uint64_t raw_id)
293 : scope_(scope), raw_id_(raw_id) {}
raw_id()294 uint64_t raw_id() const { return raw_id_; }
scope()295 const char* scope() const { return scope_; }
296
297 private:
298 const char* scope_ = nullptr;
299 uint64_t raw_id_;
300 };
301
302 class DontMangle {
303 public:
DontMangle(const void * raw_id)304 explicit DontMangle(const void* raw_id)
305 : raw_id_(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(raw_id))) {}
DontMangle(uint64_t raw_id)306 explicit DontMangle(uint64_t raw_id) : raw_id_(raw_id) {}
DontMangle(unsigned int raw_id)307 explicit DontMangle(unsigned int raw_id) : raw_id_(raw_id) {}
DontMangle(uint16_t raw_id)308 explicit DontMangle(uint16_t raw_id) : raw_id_(raw_id) {}
DontMangle(unsigned char raw_id)309 explicit DontMangle(unsigned char raw_id) : raw_id_(raw_id) {}
DontMangle(int64_t raw_id)310 explicit DontMangle(int64_t raw_id)
311 : raw_id_(static_cast<uint64_t>(raw_id)) {}
DontMangle(int raw_id)312 explicit DontMangle(int raw_id) : raw_id_(static_cast<uint64_t>(raw_id)) {}
DontMangle(int16_t raw_id)313 explicit DontMangle(int16_t raw_id)
314 : raw_id_(static_cast<uint64_t>(raw_id)) {}
DontMangle(signed char raw_id)315 explicit DontMangle(signed char raw_id)
316 : raw_id_(static_cast<uint64_t>(raw_id)) {}
DontMangle(WithScope scoped_id)317 explicit DontMangle(WithScope scoped_id)
318 : scope_(scoped_id.scope()), raw_id_(scoped_id.raw_id()) {}
scope()319 const char* scope() const { return scope_; }
raw_id()320 uint64_t raw_id() const { return raw_id_; }
321
322 private:
323 const char* scope_ = nullptr;
324 uint64_t raw_id_;
325 };
326
327 class ForceMangle {
328 public:
ForceMangle(uint64_t raw_id)329 explicit ForceMangle(uint64_t raw_id) : raw_id_(raw_id) {}
ForceMangle(unsigned int raw_id)330 explicit ForceMangle(unsigned int raw_id) : raw_id_(raw_id) {}
ForceMangle(uint16_t raw_id)331 explicit ForceMangle(uint16_t raw_id) : raw_id_(raw_id) {}
ForceMangle(unsigned char raw_id)332 explicit ForceMangle(unsigned char raw_id) : raw_id_(raw_id) {}
ForceMangle(int64_t raw_id)333 explicit ForceMangle(int64_t raw_id)
334 : raw_id_(static_cast<uint64_t>(raw_id)) {}
ForceMangle(int raw_id)335 explicit ForceMangle(int raw_id) : raw_id_(static_cast<uint64_t>(raw_id)) {}
ForceMangle(int16_t raw_id)336 explicit ForceMangle(int16_t raw_id)
337 : raw_id_(static_cast<uint64_t>(raw_id)) {}
ForceMangle(signed char raw_id)338 explicit ForceMangle(signed char raw_id)
339 : raw_id_(static_cast<uint64_t>(raw_id)) {}
raw_id()340 uint64_t raw_id() const { return raw_id_; }
341
342 private:
343 uint64_t raw_id_;
344 };
345
TraceID(const void * raw_id,unsigned int * flags)346 TraceID(const void* raw_id, unsigned int* flags)
347 : raw_id_(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(raw_id))) {
348 *flags |= TRACE_EVENT_FLAG_MANGLE_ID;
349 }
TraceID(ForceMangle raw_id,unsigned int * flags)350 TraceID(ForceMangle raw_id, unsigned int* flags) : raw_id_(raw_id.raw_id()) {
351 *flags |= TRACE_EVENT_FLAG_MANGLE_ID;
352 }
TraceID(DontMangle maybe_scoped_id,unsigned int * flags)353 TraceID(DontMangle maybe_scoped_id, unsigned int* flags)
354 : scope_(maybe_scoped_id.scope()), raw_id_(maybe_scoped_id.raw_id()) {}
TraceID(uint64_t raw_id,unsigned int * flags)355 TraceID(uint64_t raw_id, unsigned int* flags) : raw_id_(raw_id) {
356 (void)flags;
357 }
TraceID(unsigned int raw_id,unsigned int * flags)358 TraceID(unsigned int raw_id, unsigned int* flags) : raw_id_(raw_id) {
359 (void)flags;
360 }
TraceID(uint16_t raw_id,unsigned int * flags)361 TraceID(uint16_t raw_id, unsigned int* flags) : raw_id_(raw_id) {
362 (void)flags;
363 }
TraceID(unsigned char raw_id,unsigned int * flags)364 TraceID(unsigned char raw_id, unsigned int* flags) : raw_id_(raw_id) {
365 (void)flags;
366 }
TraceID(int64_t raw_id,unsigned int * flags)367 TraceID(int64_t raw_id, unsigned int* flags)
368 : raw_id_(static_cast<uint64_t>(raw_id)) {
369 (void)flags;
370 }
TraceID(int raw_id,unsigned int * flags)371 TraceID(int raw_id, unsigned int* flags)
372 : raw_id_(static_cast<uint64_t>(raw_id)) {
373 (void)flags;
374 }
TraceID(int16_t raw_id,unsigned int * flags)375 TraceID(int16_t raw_id, unsigned int* flags)
376 : raw_id_(static_cast<uint64_t>(raw_id)) {
377 (void)flags;
378 }
TraceID(signed char raw_id,unsigned int * flags)379 TraceID(signed char raw_id, unsigned int* flags)
380 : raw_id_(static_cast<uint64_t>(raw_id)) {
381 (void)flags;
382 }
TraceID(WithScope scoped_id,unsigned int * flags)383 TraceID(WithScope scoped_id, unsigned int* flags)
384 : scope_(scoped_id.scope()), raw_id_(scoped_id.raw_id()) {}
385
raw_id()386 uint64_t raw_id() const { return raw_id_; }
scope()387 const char* scope() const { return scope_; }
388
389 private:
390 const char* scope_ = nullptr;
391 uint64_t raw_id_;
392 };
393
394 // Simple union to store various types as uint64_t.
395 union TraceValueUnion {
396 bool as_bool;
397 uint64_t as_uint;
398 int64_t as_int;
399 double as_double;
400 const void* as_pointer;
401 const char* as_string;
402 };
403
404 // Simple container for const char* that should be copied instead of retained.
405 class TraceStringWithCopy {
406 public:
TraceStringWithCopy(const char * str)407 explicit TraceStringWithCopy(const char* str) : str_(str) {}
408 operator const char*() const { return str_; }
409
410 private:
411 const char* str_;
412 };
413
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)414 static V8_INLINE uint64_t AddTraceEventImpl(
415 char phase, const uint8_t* category_group_enabled, const char* name,
416 const char* scope, uint64_t id, uint64_t bind_id, int32_t num_args,
417 const char** arg_names, const uint8_t* arg_types,
418 const uint64_t* arg_values, unsigned int flags) {
419 std::unique_ptr<ConvertableToTraceFormat> arg_convertables[2];
420 if (num_args > 0 && arg_types[0] == TRACE_VALUE_TYPE_CONVERTABLE) {
421 arg_convertables[0].reset(reinterpret_cast<ConvertableToTraceFormat*>(
422 static_cast<intptr_t>(arg_values[0])));
423 }
424 if (num_args > 1 && arg_types[1] == TRACE_VALUE_TYPE_CONVERTABLE) {
425 arg_convertables[1].reset(reinterpret_cast<ConvertableToTraceFormat*>(
426 static_cast<intptr_t>(arg_values[1])));
427 }
428 DCHECK(num_args <= 2);
429 v8::Platform* platform =
430 v8::internal::tracing::TraceEventHelper::GetCurrentPlatform();
431 return platform->AddTraceEvent(phase, category_group_enabled, name, scope, id,
432 bind_id, num_args, arg_names, arg_types,
433 arg_values, arg_convertables, flags);
434 }
435
436 // Define SetTraceValue for each allowed type. It stores the type and
437 // value in the return arguments. This allows this API to avoid declaring any
438 // structures so that it is portable to third_party libraries.
439 #define INTERNAL_DECLARE_SET_TRACE_VALUE(actual_type, union_member, \
440 value_type_id) \
441 static V8_INLINE void SetTraceValue(actual_type arg, unsigned char* type, \
442 uint64_t* value) { \
443 TraceValueUnion type_value; \
444 type_value.union_member = arg; \
445 *type = value_type_id; \
446 *value = type_value.as_uint; \
447 }
448 // Simpler form for int types that can be safely casted.
449 #define INTERNAL_DECLARE_SET_TRACE_VALUE_INT(actual_type, value_type_id) \
450 static V8_INLINE void SetTraceValue(actual_type arg, unsigned char* type, \
451 uint64_t* value) { \
452 *type = value_type_id; \
453 *value = static_cast<uint64_t>(arg); \
454 }
455
INTERNAL_DECLARE_SET_TRACE_VALUE_INT(uint64_t,TRACE_VALUE_TYPE_UINT)456 INTERNAL_DECLARE_SET_TRACE_VALUE_INT(uint64_t, TRACE_VALUE_TYPE_UINT)
457 INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned int, TRACE_VALUE_TYPE_UINT)
458 INTERNAL_DECLARE_SET_TRACE_VALUE_INT(uint16_t, TRACE_VALUE_TYPE_UINT)
459 INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned char, TRACE_VALUE_TYPE_UINT)
460 INTERNAL_DECLARE_SET_TRACE_VALUE_INT(int64_t, TRACE_VALUE_TYPE_INT)
461 INTERNAL_DECLARE_SET_TRACE_VALUE_INT(int, TRACE_VALUE_TYPE_INT)
462 INTERNAL_DECLARE_SET_TRACE_VALUE_INT(int16_t, TRACE_VALUE_TYPE_INT)
463 INTERNAL_DECLARE_SET_TRACE_VALUE_INT(signed char, TRACE_VALUE_TYPE_INT)
464 INTERNAL_DECLARE_SET_TRACE_VALUE(bool, as_bool, TRACE_VALUE_TYPE_BOOL)
465 INTERNAL_DECLARE_SET_TRACE_VALUE(double, as_double, TRACE_VALUE_TYPE_DOUBLE)
466 INTERNAL_DECLARE_SET_TRACE_VALUE(const void*, as_pointer,
467 TRACE_VALUE_TYPE_POINTER)
468 INTERNAL_DECLARE_SET_TRACE_VALUE(const char*, as_string,
469 TRACE_VALUE_TYPE_STRING)
470 INTERNAL_DECLARE_SET_TRACE_VALUE(const TraceStringWithCopy&, as_string,
471 TRACE_VALUE_TYPE_COPY_STRING)
472
473 #undef INTERNAL_DECLARE_SET_TRACE_VALUE
474 #undef INTERNAL_DECLARE_SET_TRACE_VALUE_INT
475
476 static V8_INLINE void SetTraceValue(ConvertableToTraceFormat* convertable_value,
477 unsigned char* type, uint64_t* value) {
478 *type = TRACE_VALUE_TYPE_CONVERTABLE;
479 *value = static_cast<uint64_t>(reinterpret_cast<intptr_t>(convertable_value));
480 }
481
482 template <typename T>
483 static V8_INLINE typename std::enable_if<
484 std::is_convertible<T*, ConvertableToTraceFormat*>::value>::type
SetTraceValue(std::unique_ptr<T> ptr,unsigned char * type,uint64_t * value)485 SetTraceValue(std::unique_ptr<T> ptr, unsigned char* type, uint64_t* value) {
486 SetTraceValue(ptr.release(), type, value);
487 }
488
489 // These AddTraceEvent template
490 // function is defined here instead of in the macro, because the arg_values
491 // could be temporary objects, such as std::string. In order to store
492 // pointers to the internal c_str and pass through to the tracing API,
493 // the arg_values must live throughout these procedures.
494
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)495 static V8_INLINE uint64_t AddTraceEvent(char phase,
496 const uint8_t* category_group_enabled,
497 const char* name, const char* scope,
498 uint64_t id, uint64_t bind_id,
499 unsigned int flags) {
500 return TRACE_EVENT_API_ADD_TRACE_EVENT(phase, category_group_enabled, name,
501 scope, id, bind_id, kZeroNumArgs,
502 nullptr, nullptr, nullptr, flags);
503 }
504
505 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)506 static V8_INLINE uint64_t AddTraceEvent(
507 char phase, const uint8_t* category_group_enabled, const char* name,
508 const char* scope, uint64_t id, uint64_t bind_id, unsigned int flags,
509 const char* arg1_name, ARG1_TYPE&& arg1_val) {
510 const int num_args = 1;
511 uint8_t arg_type;
512 uint64_t arg_value;
513 SetTraceValue(std::forward<ARG1_TYPE>(arg1_val), &arg_type, &arg_value);
514 return TRACE_EVENT_API_ADD_TRACE_EVENT(
515 phase, category_group_enabled, name, scope, id, bind_id, num_args,
516 &arg1_name, &arg_type, &arg_value, flags);
517 }
518
519 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)520 static V8_INLINE uint64_t AddTraceEvent(
521 char phase, const uint8_t* category_group_enabled, const char* name,
522 const char* scope, uint64_t id, uint64_t bind_id, unsigned int flags,
523 const char* arg1_name, ARG1_TYPE&& arg1_val, const char* arg2_name,
524 ARG2_TYPE&& arg2_val) {
525 const int num_args = 2;
526 const char* arg_names[2] = {arg1_name, arg2_name};
527 unsigned char arg_types[2];
528 uint64_t arg_values[2];
529 SetTraceValue(std::forward<ARG1_TYPE>(arg1_val), &arg_types[0],
530 &arg_values[0]);
531 SetTraceValue(std::forward<ARG2_TYPE>(arg2_val), &arg_types[1],
532 &arg_values[1]);
533 return TRACE_EVENT_API_ADD_TRACE_EVENT(
534 phase, category_group_enabled, name, scope, id, bind_id, num_args,
535 arg_names, arg_types, arg_values, flags);
536 }
537
538 // Used by TRACE_EVENTx macros. Do not use directly.
539 class ScopedTracer {
540 public:
541 // Note: members of data_ intentionally left uninitialized. See Initialize.
ScopedTracer()542 ScopedTracer() : p_data_(NULL) {}
543
~ScopedTracer()544 ~ScopedTracer() {
545 if (p_data_ && *data_.category_group_enabled)
546 TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(
547 data_.category_group_enabled, data_.name, data_.event_handle);
548 }
549
Initialize(const uint8_t * category_group_enabled,const char * name,uint64_t event_handle)550 void Initialize(const uint8_t* category_group_enabled, const char* name,
551 uint64_t event_handle) {
552 data_.category_group_enabled = category_group_enabled;
553 data_.name = name;
554 data_.event_handle = event_handle;
555 p_data_ = &data_;
556 }
557
558 private:
559 // This Data struct workaround is to avoid initializing all the members
560 // in Data during construction of this object, since this object is always
561 // constructed, even when tracing is disabled. If the members of Data were
562 // members of this class instead, compiler warnings occur about potential
563 // uninitialized accesses.
564 struct Data {
565 const uint8_t* category_group_enabled;
566 const char* name;
567 uint64_t event_handle;
568 };
569 Data* p_data_;
570 Data data_;
571 };
572
573 // Do not use directly.
574 class CallStatsScopedTracer {
575 public:
CallStatsScopedTracer()576 CallStatsScopedTracer() : p_data_(nullptr) {}
~CallStatsScopedTracer()577 ~CallStatsScopedTracer() {
578 if (V8_UNLIKELY(p_data_ && *data_.category_group_enabled)) {
579 AddEndTraceEvent();
580 }
581 }
582
583 void Initialize(v8::internal::Isolate* isolate,
584 const uint8_t* category_group_enabled, const char* name);
585
586 private:
587 void AddEndTraceEvent();
588 struct Data {
589 const uint8_t* category_group_enabled;
590 const char* name;
591 v8::internal::Isolate* isolate;
592 };
593 bool has_parent_scope_;
594 Data* p_data_;
595 Data data_;
596 };
597
598 } // namespace tracing
599 } // namespace internal
600 } // namespace v8
601
602 #endif // SRC_TRACING_TRACE_EVENT_H_
603