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