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 164 namespace skia { 165 namespace tracing_internals { 166 167 // Specify these values when the corresponding argument of AddTraceEvent is not 168 // used. 169 const int kZeroNumArgs = 0; 170 const 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. 175 class TraceID { 176 public: 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 202 private: 203 uint64_t data_; 204 }; 205 206 // Simple union to store various types as uint64_t. 207 union 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. 217 class 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 251 INTERNAL_DECLARE_SET_TRACE_VALUE_INT(uint64_t, TRACE_VALUE_TYPE_UINT) 252 INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned int, TRACE_VALUE_TYPE_UINT) 253 INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned short, TRACE_VALUE_TYPE_UINT) 254 INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned char, TRACE_VALUE_TYPE_UINT) 255 INTERNAL_DECLARE_SET_TRACE_VALUE_INT(long long, TRACE_VALUE_TYPE_INT) 256 INTERNAL_DECLARE_SET_TRACE_VALUE_INT(long, TRACE_VALUE_TYPE_INT) 257 INTERNAL_DECLARE_SET_TRACE_VALUE_INT(int, TRACE_VALUE_TYPE_INT) 258 INTERNAL_DECLARE_SET_TRACE_VALUE_INT(short, TRACE_VALUE_TYPE_INT) 259 INTERNAL_DECLARE_SET_TRACE_VALUE_INT(signed char, TRACE_VALUE_TYPE_INT) 260 INTERNAL_DECLARE_SET_TRACE_VALUE(bool, as_bool, TRACE_VALUE_TYPE_BOOL) 261 INTERNAL_DECLARE_SET_TRACE_VALUE(double, as_double, TRACE_VALUE_TYPE_DOUBLE) 262 INTERNAL_DECLARE_SET_TRACE_VALUE(const void*, as_pointer, TRACE_VALUE_TYPE_POINTER) 263 INTERNAL_DECLARE_SET_TRACE_VALUE(const char*, as_string, TRACE_VALUE_TYPE_STRING) 264 INTERNAL_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 276 static inline SkEventTracer::Handle 277 AddTraceEvent( 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 288 template<class ARG1_TYPE> 289 static inline SkEventTracer::Handle 290 AddTraceEvent( 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 307 template<class ARG1_TYPE, class ARG2_TYPE> 308 static inline SkEventTracer::Handle 309 AddTraceEvent( 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. 331 class 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