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