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
42namespace flutter {
43
44namespace {
45
46#if defined(OS_FUCHSIA)
47template <class T, class U>
48inline 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
59class 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
240bool 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
252void 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