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 #ifndef FLUTTER_FML_TRACE_EVENT_H_
6 #define FLUTTER_FML_TRACE_EVENT_H_
7
8 #include "flutter/fml/build_config.h"
9
10 #if defined(OS_FUCHSIA)
11
12 // Forward to the system tracing mechanism on Fuchsia.
13
14 #include <lib/trace/event.h>
15
16 // TODO(DNO-448): This is disabled because the Fuchsia counter id json parsing
17 // only handles ints whereas this can produce ints or strings.
18 #define FML_TRACE_COUNTER(a, b, c, arg1, ...) \
19 ::fml::tracing::TraceCounterNopHACK((a), (b), (c), (arg1), __VA_ARGS__);
20
21 #define FML_TRACE_EVENT(a, b, args...) TRACE_DURATION(a, b)
22
23 #define TRACE_EVENT0(a, b) TRACE_DURATION(a, b)
24 #define TRACE_EVENT1(a, b, c, d) TRACE_DURATION(a, b, c, d)
25 #define TRACE_EVENT2(a, b, c, d, e, f) TRACE_DURATION(a, b, c, d, e, f)
26 #define TRACE_EVENT_ASYNC_BEGIN0(a, b, c) TRACE_ASYNC_BEGIN(a, b, c)
27 #define TRACE_EVENT_ASYNC_END0(a, b, c) TRACE_ASYNC_END(a, b, c)
28 #define TRACE_EVENT_ASYNC_BEGIN1(a, b, c, d, e) TRACE_ASYNC_BEGIN(a, b, c, d, e)
29 #define TRACE_EVENT_ASYNC_END1(a, b, c, d, e) TRACE_ASYNC_END(a, b, c, d, e)
30 #define TRACE_EVENT_INSTANT0(a, b) TRACE_INSTANT(a, b, TRACE_SCOPE_THREAD)
31
32 #endif // defined(OS_FUCHSIA)
33
34 #include <cstddef>
35 #include <cstdint>
36 #include <string>
37 #include <type_traits>
38 #include <vector>
39
40 #include "flutter/fml/macros.h"
41 #include "flutter/fml/time/time_point.h"
42
43 #if !defined(OS_FUCHSIA)
44 #ifndef TRACE_EVENT_HIDE_MACROS
45
46 #define __FML__TOKEN_CAT__(x, y) x##y
47 #define __FML__TOKEN_CAT__2(x, y) __FML__TOKEN_CAT__(x, y)
48 #define __FML__AUTO_TRACE_END(name) \
49 ::fml::tracing::ScopedInstantEnd __FML__TOKEN_CAT__2(__trace_end_, \
50 __LINE__)(name);
51
52 // This macro has the FML_ prefix so that it does not collide with the macros
53 // from lib/trace/event.h on Fuchsia.
54 //
55 // TODO(chinmaygarde): All macros here should have the FML prefix.
56 #define FML_TRACE_COUNTER(category_group, name, counter_id, arg1, ...) \
57 ::fml::tracing::TraceCounter((category_group), (name), (counter_id), (arg1), \
58 __VA_ARGS__);
59
60 #define FML_TRACE_EVENT(category_group, name, ...) \
61 ::fml::tracing::TraceEvent((category_group), (name), __VA_ARGS__); \
62 __FML__AUTO_TRACE_END(name)
63
64 #define TRACE_EVENT0(category_group, name) \
65 ::fml::tracing::TraceEvent0(category_group, name); \
66 __FML__AUTO_TRACE_END(name)
67
68 #define TRACE_EVENT1(category_group, name, arg1_name, arg1_val) \
69 ::fml::tracing::TraceEvent1(category_group, name, arg1_name, arg1_val); \
70 __FML__AUTO_TRACE_END(name)
71
72 #define TRACE_EVENT2(category_group, name, arg1_name, arg1_val, arg2_name, \
73 arg2_val) \
74 ::fml::tracing::TraceEvent2(category_group, name, arg1_name, arg1_val, \
75 arg2_name, arg2_val); \
76 __FML__AUTO_TRACE_END(name)
77
78 #define TRACE_EVENT_ASYNC_BEGIN0(category_group, name, id) \
79 ::fml::tracing::TraceEventAsyncBegin0(category_group, name, id);
80
81 #define TRACE_EVENT_ASYNC_END0(category_group, name, id) \
82 ::fml::tracing::TraceEventAsyncEnd0(category_group, name, id);
83
84 #define TRACE_EVENT_ASYNC_BEGIN1(category_group, name, id, arg1_name, \
85 arg1_val) \
86 ::fml::tracing::TraceEventAsyncBegin1(category_group, name, id, arg1_name, \
87 arg1_val);
88
89 #define TRACE_EVENT_ASYNC_END1(category_group, name, id, arg1_name, arg1_val) \
90 ::fml::tracing::TraceEventAsyncEnd1(category_group, name, id, arg1_name, \
91 arg1_val);
92
93 #define TRACE_EVENT_INSTANT0(category_group, name) \
94 ::fml::tracing::TraceEventInstant0(category_group, name);
95
96 #define TRACE_FLOW_BEGIN(category, name, id) \
97 ::fml::tracing::TraceEventFlowBegin0(category, name, id);
98
99 #define TRACE_FLOW_STEP(category, name, id) \
100 ::fml::tracing::TraceEventFlowStep0(category, name, id);
101
102 #define TRACE_FLOW_END(category, name, id) \
103 ::fml::tracing::TraceEventFlowEnd0(category, name, id);
104
105 #endif // TRACE_EVENT_HIDE_MACROS
106 #endif // !defined(OS_FUCHSIA)
107
108 namespace fml {
109 namespace tracing {
110
111 using TraceArg = const char*;
112 using TraceIDArg = int64_t;
113
114 typedef enum {
115 Event_Begin,
116 Event_End,
117 Event_UnKnow,
118 } Event_Type;
119
120 void TraceTimelineEvent(TraceArg category_group,
121 TraceArg name,
122 TraceIDArg id,
123 Event_Type type,
124 const std::vector<const char*>& names,
125 const std::vector<std::string>& values);
126
TraceToString(const char * string)127 inline std::string TraceToString(const char* string) {
128 return std::string{string};
129 }
130
TraceToString(std::string string)131 inline std::string TraceToString(std::string string) {
132 return string;
133 }
134
TraceToString(TimePoint point)135 inline std::string TraceToString(TimePoint point) {
136 return std::to_string(point.ToEpochDelta().ToNanoseconds());
137 }
138
139 template <typename T, typename = std::enable_if_t<std::is_arithmetic<T>::value>>
TraceToString(T string)140 std::string TraceToString(T string) {
141 return std::to_string(string);
142 }
143
SplitArgumentsCollect(std::vector<const char * > & keys,std::vector<std::string> & values)144 inline void SplitArgumentsCollect(std::vector<const char*>& keys,
145 std::vector<std::string>& values) {}
146
147 template <typename Key, typename Value, typename... Args>
SplitArgumentsCollect(std::vector<const char * > & keys,std::vector<std::string> & values,Key key,Value value,Args...args)148 void SplitArgumentsCollect(std::vector<const char*>& keys,
149 std::vector<std::string>& values,
150 Key key,
151 Value value,
152 Args... args) {
153 keys.emplace_back(key);
154 values.emplace_back(TraceToString(value));
155 SplitArgumentsCollect(keys, values, args...);
156 }
157
158 inline std::pair<std::vector<const char*>, std::vector<std::string>>
SplitArguments()159 SplitArguments() {
160 return {};
161 }
162
163 template <typename Key, typename Value, typename... Args>
164 std::pair<std::vector<const char*>, std::vector<std::string>>
SplitArguments(Key key,Value value,Args...args)165 SplitArguments(Key key, Value value, Args... args) {
166 std::vector<const char*> keys;
167 std::vector<std::string> values;
168 SplitArgumentsCollect(keys, values, key, value, args...);
169 return std::make_pair(std::move(keys), std::move(values));
170 }
171
172 size_t TraceNonce();
173
174 template <typename... Args>
TraceCounter(TraceArg category,TraceArg name,TraceIDArg identifier,Args...args)175 void TraceCounter(TraceArg category,
176 TraceArg name,
177 TraceIDArg identifier,
178 Args... args) {
179 auto split = SplitArguments(args...);
180 TraceTimelineEvent(category, name, identifier, Event_UnKnow,
181 split.first, split.second);
182 }
183
184 // HACK: Used to NOP FML_TRACE_COUNTER macro without triggering unused var
185 // warnings at usage sites.
186 template <typename... Args>
TraceCounterNopHACK(TraceArg category,TraceArg name,TraceIDArg identifier,Args...args)187 void TraceCounterNopHACK(TraceArg category,
188 TraceArg name,
189 TraceIDArg identifier,
190 Args... args) {}
191
192 template <typename... Args>
TraceEvent(TraceArg category,TraceArg name,Args...args)193 void TraceEvent(TraceArg category, TraceArg name, Args... args) {
194 auto split = SplitArguments(args...);
195 TraceTimelineEvent(category, name, 0, Event_Begin, split.first,
196 split.second);
197 }
198
199 void TraceEvent0(TraceArg category_group, TraceArg name);
200
201 void TraceEvent1(TraceArg category_group,
202 TraceArg name,
203 TraceArg arg1_name,
204 TraceArg arg1_val);
205
206 void TraceEvent2(TraceArg category_group,
207 TraceArg name,
208 TraceArg arg1_name,
209 TraceArg arg1_val,
210 TraceArg arg2_name,
211 TraceArg arg2_val);
212
213 void TraceEventEnd(TraceArg name);
214
215 void TraceEventAsyncComplete(TraceArg category_group,
216 TraceArg name,
217 TimePoint begin,
218 TimePoint end);
219
220 void TraceEventAsyncBegin0(TraceArg category_group,
221 TraceArg name,
222 TraceIDArg id);
223
224 void TraceEventAsyncEnd0(TraceArg category_group, TraceArg name, TraceIDArg id);
225
226 void TraceEventAsyncBegin1(TraceArg category_group,
227 TraceArg name,
228 TraceIDArg id,
229 TraceArg arg1_name,
230 TraceArg arg1_val);
231
232 void TraceEventAsyncEnd1(TraceArg category_group,
233 TraceArg name,
234 TraceIDArg id,
235 TraceArg arg1_name,
236 TraceArg arg1_val);
237
238 void TraceEventInstant0(TraceArg category_group, TraceArg name);
239
240 void TraceEventFlowBegin0(TraceArg category_group,
241 TraceArg name,
242 TraceIDArg id);
243
244 void TraceEventFlowStep0(TraceArg category_group, TraceArg name, TraceIDArg id);
245
246 void TraceEventFlowEnd0(TraceArg category_group, TraceArg name, TraceIDArg id);
247
248 class ScopedInstantEnd {
249 public:
ScopedInstantEnd(const char * str)250 ScopedInstantEnd(const char* str) : label_(str) {}
251
~ScopedInstantEnd()252 ~ScopedInstantEnd() { TraceEventEnd(label_); }
253
254 private:
255 const char* label_;
256
257 FML_DISALLOW_COPY_AND_ASSIGN(ScopedInstantEnd);
258 };
259
260 // A move-only utility object that creates a new flow with a unique ID and
261 // automatically ends it when it goes out of scope. When tracing using multiple
262 // overlapping flows, it often gets hard to make sure to end the flow
263 // (especially with early returns), or, end/step on the wrong flow. This
264 // leads to corrupted or missing traces in the UI.
265 class TraceFlow {
266 public:
TraceFlow(const char * label)267 TraceFlow(const char* label) : label_(label), nonce_(TraceNonce()) {
268 TraceEventFlowBegin0("flutter", label_, nonce_);
269 }
270
~TraceFlow()271 ~TraceFlow() { End(label_); }
272
TraceFlow(TraceFlow && other)273 TraceFlow(TraceFlow&& other) : label_(other.label_), nonce_(other.nonce_) {
274 other.nonce_ = 0;
275 }
276
Step(const char * label)277 void Step(const char* label) const {
278 TraceEventFlowStep0("flutter", label, nonce_);
279 }
280
281 void End(const char* label = nullptr) {
282 if (nonce_ != 0) {
283 TraceEventFlowEnd0("flutter", label == nullptr ? label_ : label, nonce_);
284 nonce_ = 0;
285 }
286 }
287
288 private:
289 const char* label_;
290 size_t nonce_;
291
292 FML_DISALLOW_COPY_AND_ASSIGN(TraceFlow);
293 };
294
295 } // namespace tracing
296 } // namespace fml
297
298 #endif // FLUTTER_FML_TRACE_EVENT_H_
299