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 | // FLUTTER_NOLINT |
5 | |
6 | #include "flutter/shell/common/skia_event_tracer_impl.h" |
7 | |
8 | #define TRACE_EVENT_HIDE_MACROS |
9 | #include <vector> |
10 | |
11 | #include "flutter/fml/logging.h" |
12 | #include "flutter/fml/posix_wrappers.h" |
13 | #include "flutter/fml/trace_event.h" |
14 | #include "third_party/dart/runtime/include/dart_tools_api.h" |
15 | #include "third_party/skia/include/utils/SkEventTracer.h" |
16 | #include "third_party/skia/include/utils/SkTraceEventPhase.h" |
17 | |
18 | #if defined(OS_FUCHSIA) |
19 | |
20 | #include <algorithm> |
21 | #include <cstring> |
22 | |
23 | #include <lib/trace-engine/context.h> |
24 | #include <lib/trace-engine/instrumentation.h> |
25 | |
26 | // Skia's copy of these flags are defined in a private header, so, as is |
27 | // commonly done with "trace_event_common.h" values, copy them inline here (see |
28 | // https://cs.chromium.org/chromium/src/base/trace_event/common/trace_event_common.h?l=1102-1110&rcl=239b85aeb3a6c07b33b5f162cd0ae8128eabf44d). |
29 | // |
30 | // Type values for identifying types in the TraceValue union. |
31 | #define TRACE_VALUE_TYPE_BOOL (static_cast<unsigned char>(1)) |
32 | #define TRACE_VALUE_TYPE_UINT (static_cast<unsigned char>(2)) |
33 | #define TRACE_VALUE_TYPE_INT (static_cast<unsigned char>(3)) |
34 | #define TRACE_VALUE_TYPE_DOUBLE (static_cast<unsigned char>(4)) |
35 | #define TRACE_VALUE_TYPE_POINTER (static_cast<unsigned char>(5)) |
36 | #define TRACE_VALUE_TYPE_STRING (static_cast<unsigned char>(6)) |
37 | #define TRACE_VALUE_TYPE_COPY_STRING (static_cast<unsigned char>(7)) |
38 | #define TRACE_VALUE_TYPE_CONVERTABLE (static_cast<unsigned char>(8)) |
39 | |
40 | #endif // defined(OS_FUCHSIA) |
41 | |
42 | namespace flutter { |
43 | |
44 | namespace { |
45 | |
46 | #if defined(OS_FUCHSIA) |
47 | template <class T, class U> |
48 | inline T BitCast(const U& u) { |
49 | static_assert(sizeof(T) == sizeof(U)); |
50 | |
51 | T t; |
52 | memcpy(&t, &u, sizeof(t)); |
53 | return t; |
54 | } |
55 | #endif |
56 | |
57 | } // namespace |
58 | |
59 | class FlutterEventTracer : public SkEventTracer { |
60 | public: |
61 | static constexpr const char* kSkiaTag = "skia" ; |
62 | static constexpr uint8_t kYes = 1; |
63 | static constexpr uint8_t kNo = 0; |
64 | |
65 | FlutterEventTracer(bool enabled) : enabled_(enabled ? kYes : kNo){}; |
66 | |
67 | SkEventTracer::Handle addTraceEvent(char phase, |
68 | const uint8_t* category_enabled_flag, |
69 | const char* name, |
70 | uint64_t id, |
71 | int num_args, |
72 | const char** p_arg_names, |
73 | const uint8_t* p_arg_types, |
74 | const uint64_t* p_arg_values, |
75 | uint8_t flags) override { |
76 | #if defined(OS_FUCHSIA) |
77 | static trace_site_t trace_site; |
78 | trace_string_ref_t category_ref; |
79 | trace_context_t* trace_context = trace_acquire_context_for_category_cached( |
80 | kSkiaTag, &trace_site, &category_ref); |
81 | |
82 | if (likely(!trace_context)) { |
83 | return 0; |
84 | } |
85 | |
86 | trace_ticks_t ticks = zx_ticks_get(); |
87 | |
88 | trace_thread_ref_t thread_ref; |
89 | trace_context_register_current_thread(trace_context, &thread_ref); |
90 | trace_string_ref_t name_ref; |
91 | trace_context_register_string_literal(trace_context, name, &name_ref); |
92 | |
93 | constexpr int kMaxArgs = 2; |
94 | trace_arg_t trace_args[kMaxArgs] = {}; |
95 | FML_DCHECK(num_args >= 0); |
96 | int num_trace_args = std::min(kMaxArgs, num_args); |
97 | |
98 | for (int i = 0; i < num_trace_args; i++) { |
99 | const char* arg_name = p_arg_names[i]; |
100 | const uint8_t arg_type = p_arg_types[i]; |
101 | const uint64_t arg_value = p_arg_values[i]; |
102 | |
103 | trace_string_ref_t arg_name_string_ref = |
104 | trace_context_make_registered_string_literal(trace_context, arg_name); |
105 | |
106 | trace_arg_value_t trace_arg_value; |
107 | switch (arg_type) { |
108 | case TRACE_VALUE_TYPE_BOOL: { |
109 | trace_arg_value = trace_make_bool_arg_value(!!arg_value); |
110 | break; |
111 | } |
112 | case TRACE_VALUE_TYPE_UINT: |
113 | trace_arg_value = trace_make_uint64_arg_value(arg_value); |
114 | break; |
115 | case TRACE_VALUE_TYPE_INT: |
116 | trace_arg_value = |
117 | trace_make_int64_arg_value(BitCast<int64_t>(arg_value)); |
118 | break; |
119 | case TRACE_VALUE_TYPE_DOUBLE: |
120 | trace_arg_value = |
121 | trace_make_double_arg_value(BitCast<double>(arg_value)); |
122 | break; |
123 | case TRACE_VALUE_TYPE_POINTER: |
124 | trace_arg_value = |
125 | trace_make_pointer_arg_value(BitCast<uintptr_t>(arg_value)); |
126 | break; |
127 | case TRACE_VALUE_TYPE_STRING: { |
128 | trace_string_ref_t arg_value_string_ref = |
129 | trace_context_make_registered_string_literal( |
130 | trace_context, reinterpret_cast<const char*>(arg_value)); |
131 | trace_arg_value = trace_make_string_arg_value(arg_value_string_ref); |
132 | break; |
133 | } |
134 | case TRACE_VALUE_TYPE_COPY_STRING: { |
135 | const char* arg_value_as_cstring = |
136 | reinterpret_cast<const char*>(arg_value); |
137 | trace_string_ref_t arg_value_string_ref = |
138 | trace_context_make_registered_string_copy( |
139 | trace_context, arg_value_as_cstring, |
140 | strlen(arg_value_as_cstring)); |
141 | trace_arg_value = trace_make_string_arg_value(arg_value_string_ref); |
142 | break; |
143 | } |
144 | case TRACE_VALUE_TYPE_CONVERTABLE: |
145 | trace_arg_value = trace_make_null_arg_value(); |
146 | break; |
147 | default: |
148 | trace_arg_value = trace_make_null_arg_value(); |
149 | } |
150 | |
151 | trace_args[i] = trace_make_arg(arg_name_string_ref, trace_arg_value); |
152 | } |
153 | |
154 | switch (phase) { |
155 | case TRACE_EVENT_PHASE_BEGIN: |
156 | case TRACE_EVENT_PHASE_COMPLETE: |
157 | trace_context_write_duration_begin_event_record( |
158 | trace_context, ticks, &thread_ref, &category_ref, &name_ref, |
159 | trace_args, num_trace_args); |
160 | break; |
161 | case TRACE_EVENT_PHASE_END: |
162 | trace_context_write_duration_end_event_record( |
163 | trace_context, ticks, &thread_ref, &category_ref, &name_ref, |
164 | trace_args, num_trace_args); |
165 | break; |
166 | case TRACE_EVENT_PHASE_INSTANT: |
167 | trace_context_write_instant_event_record( |
168 | trace_context, ticks, &thread_ref, &category_ref, &name_ref, |
169 | TRACE_SCOPE_THREAD, trace_args, num_trace_args); |
170 | break; |
171 | case TRACE_EVENT_PHASE_ASYNC_BEGIN: |
172 | trace_context_write_async_begin_event_record( |
173 | trace_context, ticks, &thread_ref, &category_ref, &name_ref, id, |
174 | trace_args, num_trace_args); |
175 | break; |
176 | case TRACE_EVENT_PHASE_ASYNC_END: |
177 | trace_context_write_async_end_event_record( |
178 | trace_context, ticks, &thread_ref, &category_ref, &name_ref, id, |
179 | trace_args, num_trace_args); |
180 | break; |
181 | default: |
182 | break; |
183 | } |
184 | |
185 | trace_release_context(trace_context); |
186 | |
187 | #else // defined(OS_FUCHSIA) |
188 | switch (phase) { |
189 | case TRACE_EVENT_PHASE_BEGIN: |
190 | case TRACE_EVENT_PHASE_COMPLETE: |
191 | fml::tracing::TraceEvent0(kSkiaTag, name); |
192 | break; |
193 | case TRACE_EVENT_PHASE_END: |
194 | fml::tracing::TraceEventEnd(name); |
195 | break; |
196 | case TRACE_EVENT_PHASE_INSTANT: |
197 | fml::tracing::TraceEventInstant0(kSkiaTag, name); |
198 | break; |
199 | case TRACE_EVENT_PHASE_ASYNC_BEGIN: |
200 | fml::tracing::TraceEventAsyncBegin0(kSkiaTag, name, id); |
201 | break; |
202 | case TRACE_EVENT_PHASE_ASYNC_END: |
203 | fml::tracing::TraceEventAsyncEnd0(kSkiaTag, name, id); |
204 | break; |
205 | default: |
206 | break; |
207 | } |
208 | #endif // defined(OS_FUCHSIA) |
209 | return 0; |
210 | } |
211 | |
212 | void updateTraceEventDuration(const uint8_t* category_enabled_flag, |
213 | const char* name, |
214 | SkEventTracer::Handle handle) override { |
215 | // This is only ever called from a scoped trace event so we will just end |
216 | // the section. |
217 | #if defined(OS_FUCHSIA) |
218 | TRACE_DURATION_END(kSkiaTag, name); |
219 | #else |
220 | fml::tracing::TraceEventEnd(name); |
221 | #endif |
222 | } |
223 | |
224 | const uint8_t* getCategoryGroupEnabled(const char* name) override { |
225 | return &enabled_; |
226 | } |
227 | |
228 | const char* getCategoryGroupName( |
229 | const uint8_t* category_enabled_flag) override { |
230 | return kSkiaTag; |
231 | } |
232 | |
233 | void enable() { enabled_ = kYes; } |
234 | |
235 | private: |
236 | uint8_t enabled_; |
237 | FML_DISALLOW_COPY_AND_ASSIGN(FlutterEventTracer); |
238 | }; |
239 | |
240 | bool enableSkiaTracingCallback(const char* method, |
241 | const char** param_keys, |
242 | const char** param_values, |
243 | intptr_t num_params, |
244 | void* user_data, |
245 | const char** json_object) { |
246 | FlutterEventTracer* tracer = static_cast<FlutterEventTracer*>(user_data); |
247 | tracer->enable(); |
248 | *json_object = fml::strdup("{\"type\":\"Success\"}" ); |
249 | return true; |
250 | } |
251 | |
252 | void InitSkiaEventTracer(bool enabled) { |
253 | // TODO(chinmaygarde): Leaked https://github.com/flutter/flutter/issues/30808. |
254 | auto tracer = new FlutterEventTracer(enabled); |
255 | Dart_RegisterRootServiceRequestCallback("_flutter.enableSkiaTracing" , |
256 | enableSkiaTracingCallback, |
257 | static_cast<void*>(tracer)); |
258 | // Initialize the binding to Skia's tracing events. Skia will |
259 | // take ownership of and clean up the memory allocated here. |
260 | SkEventTracer::SetInstance(tracer); |
261 | } |
262 | |
263 | } // namespace flutter |
264 | |