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