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