Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
SkTraceEvent.h
Go to the documentation of this file.
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
14#include "src/base/SkUtils.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
210namespace skia_private {
211
212// Specify these values when the corresponding argument of AddTraceEvent is not
213// used.
214const int kZeroNumArgs = 0;
215const 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.
220class TraceID {
221public:
222 TraceID(const void* id, unsigned char* flags)
223 : data_(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(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
247private:
248 uint64_t data_;
249};
250
251// Simple container for const char* that should be copied instead of retained.
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.
263template <typename T>
264static 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) {
269 *value = arg;
270 } else if constexpr (std::is_same<const char*, T>::value) {
272 *value = reinterpret_cast<uintptr_t>(arg);
273 } else if constexpr (std::is_same<TraceStringWithCopy, T>::value) {
275 *value = reinterpret_cast<uintptr_t>(static_cast<const char*>(arg));
276 } else if constexpr (std::is_pointer<T>::value) {
278 *value = reinterpret_cast<uintptr_t>(arg);
279 } else if constexpr (std::is_unsigned_v<T>) {
281 *value = arg;
282 } else if constexpr (std::is_signed_v<T>) {
284 *value = static_cast<uint64_t>(arg);
285 } else if constexpr (std::is_floating_point_v<T>) {
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.
296static 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.
300static 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
309static inline SkEventTracer::Handle
311 char phase,
312 const uint8_t* category_group_enabled,
313 const char* name,
314 uint64_t id,
315 unsigned char flags) {
317 phase, category_group_enabled, name, id,
318 kZeroNumArgs, nullptr, nullptr, nullptr, flags);
319}
320
321template<class ARG1_TYPE>
322static inline SkEventTracer::Handle
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]);
336 phase, category_group_enabled, name, id,
337 num_args, &arg1_name, arg_types, arg_values, flags);
338}
339
340template<class ARG1_TYPE, class ARG2_TYPE>
341static inline SkEventTracer::Handle
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]);
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.
365 public:
366 // Note: members of data_ intentionally left uninitialized. See Initialize.
367 ScopedTracer() : p_data_(nullptr) {}
368
370 if (p_data_ && *data_.category_group_enabled)
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
#define TRACE_EVENT_FLAG_MANGLE_ID
#define TRACE_VALUE_TYPE_STRING
#define TRACE_VALUE_TYPE_BOOL
#define TRACE_VALUE_TYPE_POINTER
#define TRACE_VALUE_TYPE_COPY_STRING
#define TRACE_VALUE_TYPE_INT
#define TRACE_VALUE_TYPE_UINT
#define TRACE_VALUE_TYPE_DOUBLE
#define TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION
#define TRACE_EVENT_API_CLASS_EXPORT
#define TRACE_EVENT_API_ADD_TRACE_EVENT
uint64_t Handle
void Initialize(const uint8_t *category_group_enabled, const char *name, SkEventTracer::Handle event_handle)
TraceID(unsigned char id, unsigned char *flags)
TraceID(uint64_t id, unsigned char *flags)
TraceID(long id, unsigned char *flags)
TraceID(signed char id, unsigned char *flags)
TraceID(unsigned int id, unsigned char *flags)
TraceID(short id, unsigned char *flags)
uint64_t data() const
TraceID(unsigned short id, unsigned char *flags)
TraceID(int id, unsigned char *flags)
TraceID(long long id, unsigned char *flags)
TraceID(const void *id, unsigned char *flags)
FlutterSemanticsFlag flags
uint8_t value
const char * name
Definition fuchsia.cc:50
static const void * TraceValueAsPointer(uint64_t value)
static const char * TraceValueAsString(uint64_t value)
const int kZeroNumArgs
static SkEventTracer::Handle AddTraceEvent(char phase, const uint8_t *category_group_enabled, const char *name, uint64_t id, unsigned char flags)
static void SetTraceValue(const T &arg, unsigned char *type, uint64_t *value)
const uint64_t kNoEventId
#define T
const uintptr_t id