1// Copyright (c) 2014 Google Inc. 2// 3// Use of this source code is governed by a BSD-style license that can be 4// found in the LICENSE file. 5 6// This header file defines implementation details of how the trace macros in 7// SkTraceEventCommon.h collect and store trace events. Anything not 8// implementation-specific should go in SkTraceEventCommon.h instead of here. 9 10#ifndef SkTraceEvent_DEFINED 11#define SkTraceEvent_DEFINED 12 13#include "SkAtomics.h" 14#include "SkEventTracer.h" 15#include "SkTraceEventCommon.h" 16 17//////////////////////////////////////////////////////////////////////////////// 18// Implementation specific tracing API definitions. 19 20// Makes it easier to add traces with a simple TRACE_EVENT0("skia", TRACE_FUNC). 21#if defined(_MSC_VER) 22 #define TRACE_FUNC __FUNCSIG__ 23#else 24 #define TRACE_FUNC __PRETTY_FUNCTION__ 25#endif 26 27// By default, const char* argument values are assumed to have long-lived scope 28// and will not be copied. Use this macro to force a const char* to be copied. 29#define TRACE_STR_COPY(str) \ 30 skia::tracing_internals::TraceStringWithCopy(str) 31 32 33#define INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE() \ 34 *INTERNAL_TRACE_EVENT_UID(category_group_enabled) & \ 35 (SkEventTracer::kEnabledForRecording_CategoryGroupEnabledFlags | \ 36 SkEventTracer::kEnabledForEventCallback_CategoryGroupEnabledFlags) 37 38// Get a pointer to the enabled state of the given trace category. Only 39// long-lived literal strings should be given as the category group. The 40// returned pointer can be held permanently in a local static for example. If 41// the unsigned char is non-zero, tracing is enabled. If tracing is enabled, 42// TRACE_EVENT_API_ADD_TRACE_EVENT can be called. It's OK if tracing is disabled 43// between the load of the tracing state and the call to 44// TRACE_EVENT_API_ADD_TRACE_EVENT, because this flag only provides an early out 45// for best performance when tracing is disabled. 46// const uint8_t* 47// TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(const char* category_group) 48#define TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED \ 49 SkEventTracer::GetInstance()->getCategoryGroupEnabled 50 51// Add a trace event to the platform tracing system. 52// SkEventTracer::Handle TRACE_EVENT_API_ADD_TRACE_EVENT( 53// char phase, 54// const uint8_t* category_group_enabled, 55// const char* name, 56// uint64_t id, 57// int num_args, 58// const char** arg_names, 59// const uint8_t* arg_types, 60// const uint64_t* arg_values, 61// unsigned char flags) 62#define TRACE_EVENT_API_ADD_TRACE_EVENT \ 63 SkEventTracer::GetInstance()->addTraceEvent 64 65// Set the duration field of a COMPLETE trace event. 66// void TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION( 67// const uint8_t* category_group_enabled, 68// const char* name, 69// SkEventTracer::Handle id) 70#define TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION \ 71 SkEventTracer::GetInstance()->updateTraceEventDuration 72 73#define TRACE_EVENT_API_ATOMIC_WORD intptr_t 74#define TRACE_EVENT_API_ATOMIC_LOAD(var) sk_atomic_load(&var, sk_memory_order_relaxed) 75#define TRACE_EVENT_API_ATOMIC_STORE(var, value) \ 76 sk_atomic_store(&var, value, sk_memory_order_relaxed) 77 78// Defines visibility for classes in trace_event.h 79#define TRACE_EVENT_API_CLASS_EXPORT SK_API 80 81// We prepend this string to all category names, so that ALL Skia trace events are 82// disabled by default when tracing in Chrome. 83#define TRACE_CATEGORY_PREFIX "disabled-by-default-" 84 85//////////////////////////////////////////////////////////////////////////////// 86 87// Implementation detail: trace event macros create temporary variables 88// to keep instrumentation overhead low. These macros give each temporary 89// variable a unique name based on the line number to prevent name collisions. 90#define INTERNAL_TRACE_EVENT_UID3(a,b) \ 91 trace_event_unique_##a##b 92#define INTERNAL_TRACE_EVENT_UID2(a,b) \ 93 INTERNAL_TRACE_EVENT_UID3(a,b) 94#define INTERNAL_TRACE_EVENT_UID(name_prefix) \ 95 INTERNAL_TRACE_EVENT_UID2(name_prefix, __LINE__) 96 97// Implementation detail: internal macro to create static category. 98// No barriers are needed, because this code is designed to operate safely 99// even when the unsigned char* points to garbage data (which may be the case 100// on processors without cache coherency). 101#define INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO_CUSTOM_VARIABLES( \ 102 category_group, atomic, category_group_enabled) \ 103 category_group_enabled = \ 104 reinterpret_cast<const uint8_t*>(TRACE_EVENT_API_ATOMIC_LOAD(atomic)); \ 105 if (!category_group_enabled) { \ 106 category_group_enabled = TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(category_group); \ 107 TRACE_EVENT_API_ATOMIC_STORE(atomic, \ 108 reinterpret_cast<TRACE_EVENT_API_ATOMIC_WORD>(category_group_enabled)); \ 109 } 110 111#define INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group) \ 112 static TRACE_EVENT_API_ATOMIC_WORD INTERNAL_TRACE_EVENT_UID(atomic) = 0; \ 113 const uint8_t* INTERNAL_TRACE_EVENT_UID(category_group_enabled); \ 114 INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO_CUSTOM_VARIABLES( \ 115 TRACE_CATEGORY_PREFIX category_group, \ 116 INTERNAL_TRACE_EVENT_UID(atomic), \ 117 INTERNAL_TRACE_EVENT_UID(category_group_enabled)); 118 119// Implementation detail: internal macro to create static category and add 120// event if the category is enabled. 121#define INTERNAL_TRACE_EVENT_ADD(phase, category_group, name, flags, ...) \ 122 do { \ 123 INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \ 124 if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \ 125 skia::tracing_internals::AddTraceEvent( \ 126 phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, \ 127 skia::tracing_internals::kNoEventId, flags, ##__VA_ARGS__); \ 128 } \ 129 } while (0) 130 131// Implementation detail: internal macro to create static category and add 132// event if the category is enabled. 133#define INTERNAL_TRACE_EVENT_ADD_WITH_ID(phase, category_group, name, id, \ 134 flags, ...) \ 135 do { \ 136 INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \ 137 if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \ 138 unsigned char trace_event_flags = flags | TRACE_EVENT_FLAG_HAS_ID; \ 139 skia::tracing_internals::TraceID trace_event_trace_id( \ 140 id, &trace_event_flags); \ 141 skia::tracing_internals::AddTraceEvent( \ 142 phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), \ 143 name, trace_event_trace_id.data(), trace_event_flags, \ 144 ##__VA_ARGS__); \ 145 } \ 146 } while (0) 147 148// Implementation detail: internal macro to create static category and add begin 149// event if the category is enabled. Also adds the end event when the scope 150// ends. 151#define INTERNAL_TRACE_EVENT_ADD_SCOPED(category_group, name, ...) \ 152 INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \ 153 skia::tracing_internals::ScopedTracer INTERNAL_TRACE_EVENT_UID(tracer); \ 154 if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \ 155 SkEventTracer::Handle h = skia::tracing_internals::AddTraceEvent( \ 156 TRACE_EVENT_PHASE_COMPLETE, \ 157 INTERNAL_TRACE_EVENT_UID(category_group_enabled), \ 158 name, skia::tracing_internals::kNoEventId, \ 159 TRACE_EVENT_FLAG_NONE, ##__VA_ARGS__); \ 160 INTERNAL_TRACE_EVENT_UID(tracer).Initialize( \ 161 INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, h); \ 162 } 163 164namespace skia { 165namespace tracing_internals { 166 167// Specify these values when the corresponding argument of AddTraceEvent is not 168// used. 169const int kZeroNumArgs = 0; 170const uint64_t kNoEventId = 0; 171 172// TraceID encapsulates an ID that can either be an integer or pointer. Pointers 173// are by default mangled with the Process ID so that they are unlikely to 174// collide when the same pointer is used on different processes. 175class TraceID { 176public: 177 TraceID(const void* id, unsigned char* flags) 178 : data_(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(id))) { 179 *flags |= TRACE_EVENT_FLAG_MANGLE_ID; 180 } 181 TraceID(uint64_t id, unsigned char* flags) 182 : data_(id) { (void)flags; } 183 TraceID(unsigned int id, unsigned char* flags) 184 : data_(id) { (void)flags; } 185 TraceID(unsigned short id, unsigned char* flags) 186 : data_(id) { (void)flags; } 187 TraceID(unsigned char id, unsigned char* flags) 188 : data_(id) { (void)flags; } 189 TraceID(long long id, unsigned char* flags) 190 : data_(static_cast<uint64_t>(id)) { (void)flags; } 191 TraceID(long id, unsigned char* flags) 192 : data_(static_cast<uint64_t>(id)) { (void)flags; } 193 TraceID(int id, unsigned char* flags) 194 : data_(static_cast<uint64_t>(id)) { (void)flags; } 195 TraceID(short id, unsigned char* flags) 196 : data_(static_cast<uint64_t>(id)) { (void)flags; } 197 TraceID(signed char id, unsigned char* flags) 198 : data_(static_cast<uint64_t>(id)) { (void)flags; } 199 200 uint64_t data() const { return data_; } 201 202private: 203 uint64_t data_; 204}; 205 206// Simple union to store various types as uint64_t. 207union TraceValueUnion { 208 bool as_bool; 209 uint64_t as_uint; 210 long long as_int; 211 double as_double; 212 const void* as_pointer; 213 const char* as_string; 214}; 215 216// Simple container for const char* that should be copied instead of retained. 217class TraceStringWithCopy { 218 public: 219 explicit TraceStringWithCopy(const char* str) : str_(str) {} 220 operator const char* () const { return str_; } 221 private: 222 const char* str_; 223}; 224 225// Define SetTraceValue for each allowed type. It stores the type and 226// value in the return arguments. This allows this API to avoid declaring any 227// structures so that it is portable to third_party libraries. 228#define INTERNAL_DECLARE_SET_TRACE_VALUE(actual_type, \ 229 union_member, \ 230 value_type_id) \ 231 static inline void SetTraceValue( \ 232 actual_type arg, \ 233 unsigned char* type, \ 234 uint64_t* value) { \ 235 TraceValueUnion type_value; \ 236 type_value.union_member = arg; \ 237 *type = value_type_id; \ 238 *value = type_value.as_uint; \ 239 } 240// Simpler form for int types that can be safely casted. 241#define INTERNAL_DECLARE_SET_TRACE_VALUE_INT(actual_type, \ 242 value_type_id) \ 243 static inline void SetTraceValue( \ 244 actual_type arg, \ 245 unsigned char* type, \ 246 uint64_t* value) { \ 247 *type = value_type_id; \ 248 *value = static_cast<uint64_t>(arg); \ 249 } 250 251INTERNAL_DECLARE_SET_TRACE_VALUE_INT(uint64_t, TRACE_VALUE_TYPE_UINT) 252INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned int, TRACE_VALUE_TYPE_UINT) 253INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned short, TRACE_VALUE_TYPE_UINT) 254INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned char, TRACE_VALUE_TYPE_UINT) 255INTERNAL_DECLARE_SET_TRACE_VALUE_INT(long long, TRACE_VALUE_TYPE_INT) 256INTERNAL_DECLARE_SET_TRACE_VALUE_INT(long, TRACE_VALUE_TYPE_INT) 257INTERNAL_DECLARE_SET_TRACE_VALUE_INT(int, TRACE_VALUE_TYPE_INT) 258INTERNAL_DECLARE_SET_TRACE_VALUE_INT(short, TRACE_VALUE_TYPE_INT) 259INTERNAL_DECLARE_SET_TRACE_VALUE_INT(signed char, TRACE_VALUE_TYPE_INT) 260INTERNAL_DECLARE_SET_TRACE_VALUE(bool, as_bool, TRACE_VALUE_TYPE_BOOL) 261INTERNAL_DECLARE_SET_TRACE_VALUE(double, as_double, TRACE_VALUE_TYPE_DOUBLE) 262INTERNAL_DECLARE_SET_TRACE_VALUE(const void*, as_pointer, TRACE_VALUE_TYPE_POINTER) 263INTERNAL_DECLARE_SET_TRACE_VALUE(const char*, as_string, TRACE_VALUE_TYPE_STRING) 264INTERNAL_DECLARE_SET_TRACE_VALUE(const TraceStringWithCopy&, as_string, 265 TRACE_VALUE_TYPE_COPY_STRING) 266 267#undef INTERNAL_DECLARE_SET_TRACE_VALUE 268#undef INTERNAL_DECLARE_SET_TRACE_VALUE_INT 269 270// These AddTraceEvent and AddTraceEvent template 271// functions are defined here instead of in the macro, because the arg_values 272// could be temporary objects, such as std::string. In order to store 273// pointers to the internal c_str and pass through to the tracing API, 274// the arg_values must live throughout these procedures. 275 276static inline SkEventTracer::Handle 277AddTraceEvent( 278 char phase, 279 const uint8_t* category_group_enabled, 280 const char* name, 281 uint64_t id, 282 unsigned char flags) { 283 return TRACE_EVENT_API_ADD_TRACE_EVENT( 284 phase, category_group_enabled, name, id, 285 kZeroNumArgs, nullptr, nullptr, nullptr, flags); 286} 287 288template<class ARG1_TYPE> 289static inline SkEventTracer::Handle 290AddTraceEvent( 291 char phase, 292 const uint8_t* category_group_enabled, 293 const char* name, 294 uint64_t id, 295 unsigned char flags, 296 const char* arg1_name, 297 const ARG1_TYPE& arg1_val) { 298 const int num_args = 1; 299 uint8_t arg_types[1]; 300 uint64_t arg_values[1]; 301 SetTraceValue(arg1_val, &arg_types[0], &arg_values[0]); 302 return TRACE_EVENT_API_ADD_TRACE_EVENT( 303 phase, category_group_enabled, name, id, 304 num_args, &arg1_name, arg_types, arg_values, flags); 305} 306 307template<class ARG1_TYPE, class ARG2_TYPE> 308static inline SkEventTracer::Handle 309AddTraceEvent( 310 char phase, 311 const uint8_t* category_group_enabled, 312 const char* name, 313 uint64_t id, 314 unsigned char flags, 315 const char* arg1_name, 316 const ARG1_TYPE& arg1_val, 317 const char* arg2_name, 318 const ARG2_TYPE& arg2_val) { 319 const int num_args = 2; 320 const char* arg_names[2] = { arg1_name, arg2_name }; 321 unsigned char arg_types[2]; 322 uint64_t arg_values[2]; 323 SetTraceValue(arg1_val, &arg_types[0], &arg_values[0]); 324 SetTraceValue(arg2_val, &arg_types[1], &arg_values[1]); 325 return TRACE_EVENT_API_ADD_TRACE_EVENT( 326 phase, category_group_enabled, name, id, 327 num_args, arg_names, arg_types, arg_values, flags); 328} 329 330// Used by TRACE_EVENTx macros. Do not use directly. 331class TRACE_EVENT_API_CLASS_EXPORT ScopedTracer { 332 public: 333 // Note: members of data_ intentionally left uninitialized. See Initialize. 334 ScopedTracer() : p_data_(nullptr) {} 335 336 ~ScopedTracer() { 337 if (p_data_ && *data_.category_group_enabled) 338 TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION( 339 data_.category_group_enabled, data_.name, data_.event_handle); 340 } 341 342 void Initialize(const uint8_t* category_group_enabled, 343 const char* name, 344 SkEventTracer::Handle event_handle) { 345 data_.category_group_enabled = category_group_enabled; 346 data_.name = name; 347 data_.event_handle = event_handle; 348 p_data_ = &data_; 349 } 350 351 private: 352 // This Data struct workaround is to avoid initializing all the members 353 // in Data during construction of this object, since this object is always 354 // constructed, even when tracing is disabled. If the members of Data were 355 // members of this class instead, compiler warnings occur about potential 356 // uninitialized accesses. 357 struct Data { 358 const uint8_t* category_group_enabled; 359 const char* name; 360 SkEventTracer::Handle event_handle; 361 }; 362 Data* p_data_; 363 Data data_; 364}; 365 366} // namespace tracing_internals 367} // namespace skia 368 369#endif 370