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