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 "SkEventTracer.h" 14 #include "SkTraceEventCommon.h" 15 #include <atomic> 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 // Defines visibility for classes in trace_event.h 74 #define TRACE_EVENT_API_CLASS_EXPORT SK_API 75 76 // We prepend this string to all category names, so that ALL Skia trace events are 77 // disabled by default when tracing in Chrome. 78 #define TRACE_CATEGORY_PREFIX "disabled-by-default-" 79 80 //////////////////////////////////////////////////////////////////////////////// 81 82 // Implementation detail: trace event macros create temporary variables 83 // to keep instrumentation overhead low. These macros give each temporary 84 // variable a unique name based on the line number to prevent name collisions. 85 #define INTERNAL_TRACE_EVENT_UID3(a,b) \ 86 trace_event_unique_##a##b 87 #define INTERNAL_TRACE_EVENT_UID2(a,b) \ 88 INTERNAL_TRACE_EVENT_UID3(a,b) 89 #define INTERNAL_TRACE_EVENT_UID(name_prefix) \ 90 INTERNAL_TRACE_EVENT_UID2(name_prefix, __LINE__) 91 92 // Implementation detail: internal macro to create static category. 93 // No barriers are needed, because this code is designed to operate safely 94 // even when the unsigned char* points to garbage data (which may be the case 95 // on processors without cache coherency). 96 #define INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO_CUSTOM_VARIABLES( \ 97 category_group, atomic, category_group_enabled) \ 98 category_group_enabled = \ 99 reinterpret_cast<const uint8_t*>(atomic.load(std::memory_order_relaxed)); \ 100 if (!category_group_enabled) { \ 101 category_group_enabled = TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(category_group); \ 102 atomic.store(reinterpret_cast<intptr_t>(category_group_enabled), \ 103 std::memory_order_relaxed); \ 104 } 105 106 #define INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group) \ 107 static std::atomic<intptr_t> INTERNAL_TRACE_EVENT_UID(atomic){0}; \ 108 const uint8_t* INTERNAL_TRACE_EVENT_UID(category_group_enabled); \ 109 INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO_CUSTOM_VARIABLES( \ 110 TRACE_CATEGORY_PREFIX category_group, \ 111 INTERNAL_TRACE_EVENT_UID(atomic), \ 112 INTERNAL_TRACE_EVENT_UID(category_group_enabled)); 113 114 // Implementation detail: internal macro to create static category and add 115 // event if the category is enabled. 116 #define INTERNAL_TRACE_EVENT_ADD(phase, category_group, name, flags, ...) \ 117 do { \ 118 INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \ 119 if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \ 120 skia::tracing_internals::AddTraceEvent( \ 121 phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, \ 122 skia::tracing_internals::kNoEventId, flags, ##__VA_ARGS__); \ 123 } \ 124 } while (0) 125 126 // Implementation detail: internal macro to create static category and add 127 // event if the category is enabled. 128 #define INTERNAL_TRACE_EVENT_ADD_WITH_ID(phase, category_group, name, id, \ 129 flags, ...) \ 130 do { \ 131 INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \ 132 if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \ 133 unsigned char trace_event_flags = flags | TRACE_EVENT_FLAG_HAS_ID; \ 134 skia::tracing_internals::TraceID trace_event_trace_id( \ 135 id, &trace_event_flags); \ 136 skia::tracing_internals::AddTraceEvent( \ 137 phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), \ 138 name, trace_event_trace_id.data(), trace_event_flags, \ 139 ##__VA_ARGS__); \ 140 } \ 141 } while (0) 142 143 // Implementation detail: internal macro to create static category and add begin 144 // event if the category is enabled. Also adds the end event when the scope 145 // ends. 146 #define INTERNAL_TRACE_EVENT_ADD_SCOPED(category_group, name, ...) \ 147 INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \ 148 skia::tracing_internals::ScopedTracer INTERNAL_TRACE_EVENT_UID(tracer); \ 149 do { \ 150 if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \ 151 SkEventTracer::Handle h = skia::tracing_internals::AddTraceEvent( \ 152 TRACE_EVENT_PHASE_COMPLETE, \ 153 INTERNAL_TRACE_EVENT_UID(category_group_enabled), \ 154 name, skia::tracing_internals::kNoEventId, \ 155 TRACE_EVENT_FLAG_NONE, ##__VA_ARGS__); \ 156 INTERNAL_TRACE_EVENT_UID(tracer).Initialize( \ 157 INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, h); \ 158 } \ 159 } while (0) 160 161 namespace skia { 162 namespace tracing_internals { 163 164 // Specify these values when the corresponding argument of AddTraceEvent is not 165 // used. 166 const int kZeroNumArgs = 0; 167 const uint64_t kNoEventId = 0; 168 169 // TraceID encapsulates an ID that can either be an integer or pointer. Pointers 170 // are by default mangled with the Process ID so that they are unlikely to 171 // collide when the same pointer is used on different processes. 172 class TraceID { 173 public: 174 TraceID(const void* id, unsigned char* flags) 175 : data_(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(id))) { 176 *flags |= TRACE_EVENT_FLAG_MANGLE_ID; 177 } 178 TraceID(uint64_t id, unsigned char* flags) 179 : data_(id) { (void)flags; } 180 TraceID(unsigned int id, unsigned char* flags) 181 : data_(id) { (void)flags; } 182 TraceID(unsigned short id, unsigned char* flags) 183 : data_(id) { (void)flags; } 184 TraceID(unsigned char id, unsigned char* flags) 185 : data_(id) { (void)flags; } 186 TraceID(long long id, unsigned char* flags) 187 : data_(static_cast<uint64_t>(id)) { (void)flags; } 188 TraceID(long id, unsigned char* flags) 189 : data_(static_cast<uint64_t>(id)) { (void)flags; } 190 TraceID(int id, unsigned char* flags) 191 : data_(static_cast<uint64_t>(id)) { (void)flags; } 192 TraceID(short id, unsigned char* flags) 193 : data_(static_cast<uint64_t>(id)) { (void)flags; } 194 TraceID(signed char id, unsigned char* flags) 195 : data_(static_cast<uint64_t>(id)) { (void)flags; } 196 197 uint64_t data() const { return data_; } 198 199 private: 200 uint64_t data_; 201 }; 202 203 // Simple union to store various types as uint64_t. 204 union TraceValueUnion { 205 bool as_bool; 206 uint64_t as_uint; 207 long long as_int; 208 double as_double; 209 const void* as_pointer; 210 const char* as_string; 211 }; 212 213 // Simple container for const char* that should be copied instead of retained. 214 class TraceStringWithCopy { 215 public: 216 explicit TraceStringWithCopy(const char* str) : str_(str) {} 217 operator const char* () const { return str_; } 218 private: 219 const char* str_; 220 }; 221 222 // Define SetTraceValue for each allowed type. It stores the type and 223 // value in the return arguments. This allows this API to avoid declaring any 224 // structures so that it is portable to third_party libraries. 225 #define INTERNAL_DECLARE_SET_TRACE_VALUE(actual_type, \ 226 union_member, \ 227 value_type_id) \ 228 static inline void SetTraceValue( \ 229 actual_type arg, \ 230 unsigned char* type, \ 231 uint64_t* value) { \ 232 TraceValueUnion type_value; \ 233 type_value.union_member = arg; \ 234 *type = value_type_id; \ 235 *value = type_value.as_uint; \ 236 } 237 // Simpler form for int types that can be safely casted. 238 #define INTERNAL_DECLARE_SET_TRACE_VALUE_INT(actual_type, \ 239 value_type_id) \ 240 static inline void SetTraceValue( \ 241 actual_type arg, \ 242 unsigned char* type, \ 243 uint64_t* value) { \ 244 *type = value_type_id; \ 245 *value = static_cast<uint64_t>(arg); \ 246 } 247 248 INTERNAL_DECLARE_SET_TRACE_VALUE_INT(uint64_t, TRACE_VALUE_TYPE_UINT) 249 INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned int, TRACE_VALUE_TYPE_UINT) 250 INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned short, TRACE_VALUE_TYPE_UINT) 251 INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned char, TRACE_VALUE_TYPE_UINT) 252 INTERNAL_DECLARE_SET_TRACE_VALUE_INT(long long, TRACE_VALUE_TYPE_INT) 253 INTERNAL_DECLARE_SET_TRACE_VALUE_INT(long, TRACE_VALUE_TYPE_INT) 254 INTERNAL_DECLARE_SET_TRACE_VALUE_INT(int, TRACE_VALUE_TYPE_INT) 255 INTERNAL_DECLARE_SET_TRACE_VALUE_INT(short, TRACE_VALUE_TYPE_INT) 256 INTERNAL_DECLARE_SET_TRACE_VALUE_INT(signed char, TRACE_VALUE_TYPE_INT) 257 INTERNAL_DECLARE_SET_TRACE_VALUE(bool, as_bool, TRACE_VALUE_TYPE_BOOL) 258 INTERNAL_DECLARE_SET_TRACE_VALUE(double, as_double, TRACE_VALUE_TYPE_DOUBLE) 259 INTERNAL_DECLARE_SET_TRACE_VALUE(const void*, as_pointer, TRACE_VALUE_TYPE_POINTER) 260 INTERNAL_DECLARE_SET_TRACE_VALUE(const char*, as_string, TRACE_VALUE_TYPE_STRING) 261 INTERNAL_DECLARE_SET_TRACE_VALUE(const TraceStringWithCopy&, as_string, 262 TRACE_VALUE_TYPE_COPY_STRING) 263 264 #undef INTERNAL_DECLARE_SET_TRACE_VALUE 265 #undef INTERNAL_DECLARE_SET_TRACE_VALUE_INT 266 267 // These AddTraceEvent and AddTraceEvent template 268 // functions are defined here instead of in the macro, because the arg_values 269 // could be temporary objects, such as std::string. In order to store 270 // pointers to the internal c_str and pass through to the tracing API, 271 // the arg_values must live throughout these procedures. 272 273 static inline SkEventTracer::Handle 274 AddTraceEvent( 275 char phase, 276 const uint8_t* category_group_enabled, 277 const char* name, 278 uint64_t id, 279 unsigned char flags) { 280 return TRACE_EVENT_API_ADD_TRACE_EVENT( 281 phase, category_group_enabled, name, id, 282 kZeroNumArgs, nullptr, nullptr, nullptr, flags); 283 } 284 285 template<class ARG1_TYPE> 286 static inline SkEventTracer::Handle 287 AddTraceEvent( 288 char phase, 289 const uint8_t* category_group_enabled, 290 const char* name, 291 uint64_t id, 292 unsigned char flags, 293 const char* arg1_name, 294 const ARG1_TYPE& arg1_val) { 295 const int num_args = 1; 296 uint8_t arg_types[1]; 297 uint64_t arg_values[1]; 298 SetTraceValue(arg1_val, &arg_types[0], &arg_values[0]); 299 return TRACE_EVENT_API_ADD_TRACE_EVENT( 300 phase, category_group_enabled, name, id, 301 num_args, &arg1_name, arg_types, arg_values, flags); 302 } 303 304 template<class ARG1_TYPE, class ARG2_TYPE> 305 static inline SkEventTracer::Handle 306 AddTraceEvent( 307 char phase, 308 const uint8_t* category_group_enabled, 309 const char* name, 310 uint64_t id, 311 unsigned char flags, 312 const char* arg1_name, 313 const ARG1_TYPE& arg1_val, 314 const char* arg2_name, 315 const ARG2_TYPE& arg2_val) { 316 const int num_args = 2; 317 const char* arg_names[2] = { arg1_name, arg2_name }; 318 unsigned char arg_types[2]; 319 uint64_t arg_values[2]; 320 SetTraceValue(arg1_val, &arg_types[0], &arg_values[0]); 321 SetTraceValue(arg2_val, &arg_types[1], &arg_values[1]); 322 return TRACE_EVENT_API_ADD_TRACE_EVENT( 323 phase, category_group_enabled, name, id, 324 num_args, arg_names, arg_types, arg_values, flags); 325 } 326 327 // Used by TRACE_EVENTx macros. Do not use directly. 328 class TRACE_EVENT_API_CLASS_EXPORT ScopedTracer { 329 public: 330 // Note: members of data_ intentionally left uninitialized. See Initialize. 331 ScopedTracer() : p_data_(nullptr) {} 332 333 ~ScopedTracer() { 334 if (p_data_ && *data_.category_group_enabled) 335 TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION( 336 data_.category_group_enabled, data_.name, data_.event_handle); 337 } 338 339 void Initialize(const uint8_t* category_group_enabled, 340 const char* name, 341 SkEventTracer::Handle event_handle) { 342 data_.category_group_enabled = category_group_enabled; 343 data_.name = name; 344 data_.event_handle = event_handle; 345 p_data_ = &data_; 346 } 347 348 private: 349 // This Data struct workaround is to avoid initializing all the members 350 // in Data during construction of this object, since this object is always 351 // constructed, even when tracing is disabled. If the members of Data were 352 // members of this class instead, compiler warnings occur about potential 353 // uninitialized accesses. 354 struct Data { 355 const uint8_t* category_group_enabled; 356 const char* name; 357 SkEventTracer::Handle event_handle; 358 }; 359 Data* p_data_; 360 Data data_; 361 }; 362 363 } // namespace tracing_internals 364 } // namespace skia 365 366 #endif 367