Flutter Engine
 
Loading...
Searching...
No Matches
skia_event_tracer_impl.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
6
7#define TRACE_EVENT_HIDE_MACROS
8#include <map>
9#include <set>
10#include <vector>
11
12#include "flutter/fml/logging.h"
15#include "third_party/dart/runtime/include/dart_tools_api.h"
16#include "third_party/skia/include/utils/SkEventTracer.h"
17#include "third_party/skia/include/utils/SkTraceEventPhase.h"
18
19#if defined(OS_FUCHSIA)
20
21#include <algorithm>
22#include <cstring>
23
24#include <lib/trace-engine/context.h>
25#include <lib/trace-engine/instrumentation.h>
26
27// Skia's copy of these flags are defined in a private header, so, as is
28// commonly done with "trace_event_common.h" values, copy them inline here (see
29// https://cs.chromium.org/chromium/src/base/trace_event/common/trace_event_common.h?l=1102-1110&rcl=239b85aeb3a6c07b33b5f162cd0ae8128eabf44d).
30//
31// Type values for identifying types in the TraceValue union.
32#define TRACE_VALUE_TYPE_BOOL (static_cast<unsigned char>(1))
33#define TRACE_VALUE_TYPE_UINT (static_cast<unsigned char>(2))
34#define TRACE_VALUE_TYPE_INT (static_cast<unsigned char>(3))
35#define TRACE_VALUE_TYPE_DOUBLE (static_cast<unsigned char>(4))
36#define TRACE_VALUE_TYPE_POINTER (static_cast<unsigned char>(5))
37#define TRACE_VALUE_TYPE_STRING (static_cast<unsigned char>(6))
38#define TRACE_VALUE_TYPE_COPY_STRING (static_cast<unsigned char>(7))
39#define TRACE_VALUE_TYPE_CONVERTABLE (static_cast<unsigned char>(8))
40
41#endif // defined(OS_FUCHSIA)
42
43namespace flutter {
44
45namespace {
46
47// Skia prepends this string to the category names of its trace events.
48// Defined in Skia's src/core/SkTraceEvent.h.
49constexpr std::string_view kTraceCategoryPrefix = "disabled-by-default-";
50
51// Category name used for shader compilation events.
52constexpr std::string_view kShaderCategoryName =
53 "disabled-by-default-skia.shaders";
54
55#if !defined(OS_FUCHSIA)
56// Argument name of the tag used by DevTools.
57constexpr char kDevtoolsTagArg[] = "devtoolsTag";
58
59// DevtoolsTag value for shader events.
60constexpr char kShadersDevtoolsTag[] = "shaders";
61#endif // !defined(OS_FUCHSIA)
62
63#if defined(OS_FUCHSIA)
64template <class T, class U>
65inline T BitCast(const U& u) {
66 static_assert(sizeof(T) == sizeof(U));
67
68 T t;
69 memcpy(&t, &u, sizeof(t));
70 return t;
71}
72#endif // defined(OS_FUCHSIA)
73
74} // namespace
75
76class FlutterEventTracer : public SkEventTracer {
77 public:
78 static constexpr const char* kSkiaTag = "skia";
79 static constexpr uint8_t kYes = 1;
80 static constexpr uint8_t kNo = 0;
81
82 FlutterEventTracer(bool enabled,
83 const std::optional<std::vector<std::string>>& allowlist)
84 : enabled_(enabled ? kYes : kNo) {
85 if (allowlist.has_value()) {
86 allowlist_.emplace();
87 for (const std::string& category : *allowlist) {
88 allowlist_->insert(std::string(kTraceCategoryPrefix) + category);
89 }
90 }
91 };
92
93 SkEventTracer::Handle addTraceEvent(char phase,
94 const uint8_t* category_enabled_flag,
95 const char* name,
96 uint64_t id,
97 int num_args,
98 const char** p_arg_names,
99 const uint8_t* p_arg_types,
100 const uint64_t* p_arg_values,
101 uint8_t flags) override {
102#if defined(OS_FUCHSIA)
103 static trace_site_t trace_site;
104 trace_string_ref_t category_ref;
105 trace_context_t* trace_context = trace_acquire_context_for_category_cached(
106 kSkiaTag, &trace_site, &category_ref);
107
108 if (likely(!trace_context)) {
109 return 0;
110 }
111
112 trace_ticks_t ticks = zx_ticks_get();
113
114 trace_thread_ref_t thread_ref;
115 trace_context_register_current_thread(trace_context, &thread_ref);
116 trace_string_ref_t name_ref;
117 trace_context_register_string_literal(trace_context, name, &name_ref);
118
119 constexpr int kMaxArgs = 2;
120 trace_arg_t trace_args[kMaxArgs] = {};
121 FML_DCHECK(num_args >= 0);
122 int num_trace_args = std::min(kMaxArgs, num_args);
123
124 for (int i = 0; i < num_trace_args; i++) {
125 const char* arg_name = p_arg_names[i];
126 const uint8_t arg_type = p_arg_types[i];
127 const uint64_t arg_value = p_arg_values[i];
128
129 trace_string_ref_t arg_name_string_ref =
130 trace_context_make_registered_string_literal(trace_context, arg_name);
131
132 trace_arg_value_t trace_arg_value;
133 switch (arg_type) {
134 case TRACE_VALUE_TYPE_BOOL: {
135 trace_arg_value = trace_make_bool_arg_value(!!arg_value);
136 break;
137 }
138 case TRACE_VALUE_TYPE_UINT:
139 trace_arg_value = trace_make_uint64_arg_value(arg_value);
140 break;
141 case TRACE_VALUE_TYPE_INT:
142 trace_arg_value =
143 trace_make_int64_arg_value(BitCast<int64_t>(arg_value));
144 break;
145 case TRACE_VALUE_TYPE_DOUBLE:
146 trace_arg_value =
147 trace_make_double_arg_value(BitCast<double>(arg_value));
148 break;
149 case TRACE_VALUE_TYPE_POINTER:
150 trace_arg_value =
151 trace_make_pointer_arg_value(BitCast<uintptr_t>(arg_value));
152 break;
153 case TRACE_VALUE_TYPE_STRING: {
154 trace_string_ref_t arg_value_string_ref =
155 trace_context_make_registered_string_literal(
156 trace_context, reinterpret_cast<const char*>(arg_value));
157 trace_arg_value = trace_make_string_arg_value(arg_value_string_ref);
158 break;
159 }
160 case TRACE_VALUE_TYPE_COPY_STRING: {
161 const char* arg_value_as_cstring =
162 reinterpret_cast<const char*>(arg_value);
163 trace_string_ref_t arg_value_string_ref =
164 trace_context_make_registered_string_copy(
165 trace_context, arg_value_as_cstring,
166 strlen(arg_value_as_cstring));
167 trace_arg_value = trace_make_string_arg_value(arg_value_string_ref);
168 break;
169 }
170 case TRACE_VALUE_TYPE_CONVERTABLE:
171 trace_arg_value = trace_make_null_arg_value();
172 break;
173 default:
174 trace_arg_value = trace_make_null_arg_value();
175 }
176
177 trace_args[i] = trace_make_arg(arg_name_string_ref, trace_arg_value);
178 }
179
180 switch (phase) {
181 case TRACE_EVENT_PHASE_BEGIN:
182 case TRACE_EVENT_PHASE_COMPLETE:
183 trace_context_write_duration_begin_event_record(
184 trace_context, ticks, &thread_ref, &category_ref, &name_ref,
185 trace_args, num_trace_args);
186 break;
187 case TRACE_EVENT_PHASE_END:
188 trace_context_write_duration_end_event_record(
189 trace_context, ticks, &thread_ref, &category_ref, &name_ref,
190 trace_args, num_trace_args);
191 break;
192 case TRACE_EVENT_PHASE_INSTANT:
193 trace_context_write_instant_event_record(
194 trace_context, ticks, &thread_ref, &category_ref, &name_ref,
195 TRACE_SCOPE_THREAD, trace_args, num_trace_args);
196 break;
197 case TRACE_EVENT_PHASE_ASYNC_BEGIN:
198 trace_context_write_async_begin_event_record(
199 trace_context, ticks, &thread_ref, &category_ref, &name_ref, id,
200 trace_args, num_trace_args);
201 break;
202 case TRACE_EVENT_PHASE_ASYNC_END:
203 trace_context_write_async_end_event_record(
204 trace_context, ticks, &thread_ref, &category_ref, &name_ref, id,
205 trace_args, num_trace_args);
206 break;
207 default:
208 break;
209 }
210
211 trace_release_context(trace_context);
212
213#else // defined(OS_FUCHSIA)
214 const char* devtoolsTag = nullptr;
215 if (shaders_category_flag_ &&
216 category_enabled_flag == shaders_category_flag_) {
217 devtoolsTag = kShadersDevtoolsTag;
218 }
219 switch (phase) {
220 case TRACE_EVENT_PHASE_BEGIN:
221 case TRACE_EVENT_PHASE_COMPLETE:
222 if (devtoolsTag) {
223 fml::tracing::TraceEvent1(kSkiaTag, name, /*flow_id_count=*/0,
224 /*flow_ids=*/nullptr, kDevtoolsTagArg,
225 devtoolsTag);
226 } else {
227 fml::tracing::TraceEvent0(kSkiaTag, name, /*flow_id_count=*/0,
228 /*flow_ids=*/nullptr);
229 }
230 break;
231 case TRACE_EVENT_PHASE_END:
233 break;
234 case TRACE_EVENT_PHASE_INSTANT:
235 if (devtoolsTag) {
237 /*flow_id_count=*/0,
238 /*flow_ids=*/nullptr,
239 kDevtoolsTagArg, devtoolsTag);
240 } else {
242 /*flow_id_count=*/0,
243 /*flow_ids=*/nullptr);
244 }
245 break;
246 case TRACE_EVENT_PHASE_ASYNC_BEGIN:
247 if (devtoolsTag) {
249 /*flow_id_count=*/0,
250 /*flow_ids=*/nullptr,
251 kDevtoolsTagArg, devtoolsTag);
252 } else {
254 /*flow_id_count=*/0,
255 /*flow_ids=*/nullptr);
256 }
257 break;
258 case TRACE_EVENT_PHASE_ASYNC_END:
259 if (devtoolsTag) {
260 fml::tracing::TraceEventAsyncEnd1(kSkiaTag, name, id, kDevtoolsTagArg,
261 devtoolsTag);
262 } else {
264 }
265 break;
266 default:
267 break;
268 }
269#endif // defined(OS_FUCHSIA)
270 return 0;
271 }
272
273 void updateTraceEventDuration(const uint8_t* category_enabled_flag,
274 const char* name,
275 SkEventTracer::Handle handle) override {
276 // This is only ever called from a scoped trace event so we will just end
277 // the section.
278#if defined(OS_FUCHSIA)
279 TRACE_DURATION_END(kSkiaTag, name);
280#else
282#endif
283 }
284
285 const uint8_t* getCategoryGroupEnabled(const char* name) override {
286 // Skia will only use long-lived string literals as event names.
287 std::lock_guard<std::mutex> lock(flag_map_mutex_);
288 auto flag_it = category_flag_map_.find(name);
289 if (flag_it == category_flag_map_.end()) {
290 bool allowed;
291 if (enabled_) {
292 allowed = !allowlist_.has_value() ||
293 allowlist_->find(name) != allowlist_->end();
294 } else {
295 allowed = false;
296 }
297 flag_it = category_flag_map_.insert(std::make_pair(name, allowed)).first;
298 const uint8_t* flag = &flag_it->second;
299 reverse_flag_map_.insert(std::make_pair(flag, name));
300 if (kShaderCategoryName == name) {
301 shaders_category_flag_ = flag;
302 }
303 }
304 return &flag_it->second;
305 }
306
308 const uint8_t* category_enabled_flag) override {
309 std::lock_guard<std::mutex> lock(flag_map_mutex_);
310 auto reverse_it = reverse_flag_map_.find(category_enabled_flag);
311 if (reverse_it != reverse_flag_map_.end()) {
312 return reverse_it->second;
313 } else {
314 return kSkiaTag;
315 }
316 }
317
318 private:
319 uint8_t enabled_;
320 std::optional<std::set<std::string>> allowlist_;
321 std::mutex flag_map_mutex_;
322 std::map<const char*, uint8_t> category_flag_map_;
323 std::map<const uint8_t*, const char*> reverse_flag_map_;
324 const uint8_t* shaders_category_flag_ = nullptr;
326};
327
329 bool enabled,
330 const std::optional<std::vector<std::string>>& allowlist) {
331 auto tracer = new FlutterEventTracer(enabled, allowlist);
332 // Initialize the binding to Skia's tracing events. Skia will
333 // take ownership of and clean up the memory allocated here.
334 SkEventTracer::SetInstance(tracer);
335}
336
337} // namespace flutter
void updateTraceEventDuration(const uint8_t *category_enabled_flag, const char *name, SkEventTracer::Handle handle) override
FlutterEventTracer(bool enabled, const std::optional< std::vector< std::string > > &allowlist)
static constexpr const char * kSkiaTag
const uint8_t * getCategoryGroupEnabled(const char *name) override
SkEventTracer::Handle addTraceEvent(char phase, const uint8_t *category_enabled_flag, const char *name, uint64_t id, int num_args, const char **p_arg_names, const uint8_t *p_arg_types, const uint64_t *p_arg_values, uint8_t flags) override
const char * getCategoryGroupName(const uint8_t *category_enabled_flag) override
#define FML_DCHECK(condition)
Definition logging.h:122
#define FML_DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition macros.h:27
void InitSkiaEventTracer(bool enabled, const std::optional< std::vector< std::string > > &allowlist)
DEF_SWITCHES_START aot vmservice shared library name
Definition switch_defs.h:27
void TraceEventInstant0(TraceArg category_group, TraceArg name, size_t flow_id_count, const uint64_t *flow_ids)
void TraceEventAsyncBegin0(TraceArg category_group, TraceArg name, TraceIDArg id, size_t flow_id_count, const uint64_t *flow_ids)
void TraceEventAsyncEnd0(TraceArg category_group, TraceArg name, TraceIDArg id)
void TraceEvent0(TraceArg category_group, TraceArg name, size_t flow_id_count, const uint64_t *flow_ids)
void TraceEventInstant1(TraceArg category_group, TraceArg name, size_t flow_id_count, const uint64_t *flow_ids, TraceArg arg1_name, TraceArg arg1_val)
void TraceEventAsyncBegin1(TraceArg category_group, TraceArg name, TraceIDArg id, size_t flow_id_count, const uint64_t *flow_ids, TraceArg arg1_name, TraceArg arg1_val)
void TraceEventAsyncEnd1(TraceArg category_group, TraceArg name, TraceIDArg id, TraceArg arg1_name, TraceArg arg1_val)
void TraceEventEnd(TraceArg name)
void TraceEvent1(TraceArg category_group, TraceArg name, size_t flow_id_count, const uint64_t *flow_ids, TraceArg arg1_name, TraceArg arg1_val)