• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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