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