Flutter Engine
The 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
5#include "flutter/shell/common/skia_event_tracer_impl.h"
6
7#define TRACE_EVENT_HIDE_MACROS
8#include <map>
9#include <set>
10#include <vector>
11
12#include "flutter/fml/logging.h"
13#include "flutter/fml/posix_wrappers.h"
14#include "flutter/fml/trace_event.h"
15#include "third_party/dart/runtime/include/dart_tools_api.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
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
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) {
135 trace_arg_value = trace_make_bool_arg_value(!!arg_value);
136 break;
137 }
139 trace_arg_value = trace_make_uint64_arg_value(arg_value);
140 break;
142 trace_arg_value =
143 trace_make_int64_arg_value(BitCast<int64_t>(arg_value));
144 break;
146 trace_arg_value =
147 trace_make_double_arg_value(BitCast<double>(arg_value));
148 break;
150 trace_arg_value =
151 trace_make_pointer_arg_value(BitCast<uintptr_t>(arg_value));
152 break;
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 }
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 }
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) {
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;
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;
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;
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;
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) {
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;
233 break;
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;
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;
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.
335}
336
337} // namespace flutter
#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_VALUE_TYPE_CONVERTABLE
#define TRACE_EVENT_PHASE_ASYNC_BEGIN
#define TRACE_EVENT_PHASE_END
#define TRACE_EVENT_PHASE_BEGIN
#define TRACE_EVENT_PHASE_INSTANT
#define TRACE_EVENT_PHASE_COMPLETE
#define TRACE_EVENT_PHASE_ASYNC_END
uint64_t Handle
static bool SetInstance(SkEventTracer *, bool leakTracer=false)
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
FlutterSemanticsFlag flag
FlutterSemanticsFlag flags
#define FML_DCHECK(condition)
Definition logging.h:103
#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 switches.h:32
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace Enable an endless trace buffer The default is a ring buffer This is useful when very old events need to viewed For during application launch Memory usage will continue to grow indefinitely however Start app with an specific route defined on the framework flutter assets Path to the Flutter assets directory enable service port Allow the VM service to fallback to automatic port selection if binding to a specified port fails trace Trace early application lifecycle Automatically switches to an endless trace buffer trace skia allowlist
Definition switches.h:171
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)
#define T