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