xref: /aosp_15_r20/external/skia/src/core/SkTraceEvent.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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"
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:
TraceID(const void * id,unsigned char * flags)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     }
TraceID(uint64_t id,unsigned char * flags)226     TraceID(uint64_t id, unsigned char* flags)
227         : data_(id) { (void)flags; }
TraceID(unsigned int id,unsigned char * flags)228     TraceID(unsigned int id, unsigned char* flags)
229         : data_(id) { (void)flags; }
TraceID(unsigned short id,unsigned char * flags)230     TraceID(unsigned short id, unsigned char* flags)
231         : data_(id) { (void)flags; }
TraceID(unsigned char id,unsigned char * flags)232     TraceID(unsigned char id, unsigned char* flags)
233         : data_(id) { (void)flags; }
TraceID(long long id,unsigned char * flags)234     TraceID(long long id, unsigned char* flags)
235         : data_(static_cast<uint64_t>(id)) { (void)flags; }
TraceID(long id,unsigned char * flags)236     TraceID(long id, unsigned char* flags)
237         : data_(static_cast<uint64_t>(id)) { (void)flags; }
TraceID(int id,unsigned char * flags)238     TraceID(int id, unsigned char* flags)
239         : data_(static_cast<uint64_t>(id)) { (void)flags; }
TraceID(short id,unsigned char * flags)240     TraceID(short id, unsigned char* flags)
241         : data_(static_cast<uint64_t>(id)) { (void)flags; }
TraceID(signed char id,unsigned char * flags)242     TraceID(signed char id, unsigned char* flags)
243         : data_(static_cast<uint64_t>(id)) { (void)flags; }
244 
data()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:
TraceStringWithCopy(const char * str)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>
SetTraceValue(const T & arg,unsigned char * type,uint64_t * value)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.
TraceValueAsString(uint64_t value)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.
TraceValueAsPointer(uint64_t value)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
AddTraceEvent(char phase,const uint8_t * category_group_enabled,const char * name,uint64_t id,unsigned char flags)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
AddTraceEvent(char phase,const uint8_t * category_group_enabled,const char * name,uint64_t id,unsigned char flags,const char * arg1_name,const ARG1_TYPE & arg1_val)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
AddTraceEvent(char phase,const uint8_t * category_group_enabled,const char * name,uint64_t id,unsigned char flags,const char * arg1_name,const ARG1_TYPE & arg1_val,const char * arg2_name,const ARG2_TYPE & arg2_val)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.
ScopedTracer()367   ScopedTracer() : p_data_(nullptr) {}
368 
~ScopedTracer()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 
Initialize(const uint8_t * category_group_enabled,const char * name,SkEventTracer::Handle event_handle)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
404