• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef INCLUDE_PERFETTO_TRACING_TRACK_EVENT_H_
18 #define INCLUDE_PERFETTO_TRACING_TRACK_EVENT_H_
19 
20 #include "perfetto/base/time.h"
21 #include "perfetto/tracing/internal/track_event_data_source.h"
22 #include "perfetto/tracing/internal/track_event_internal.h"
23 #include "perfetto/tracing/internal/track_event_macros.h"
24 #include "perfetto/tracing/track.h"
25 #include "perfetto/tracing/track_event_category_registry.h"
26 #include "protos/perfetto/trace/track_event/track_event.pbzero.h"
27 
28 #include <type_traits>
29 
30 // This file contains a set of macros designed for instrumenting applications
31 // with track event trace points. While the underlying TrackEvent API can also
32 // be used directly, doing so efficiently requires some care (e.g., to avoid
33 // evaluating arguments while tracing is disabled). These types of optimizations
34 // are abstracted away by the macros below.
35 //
36 // ================
37 // Quickstart guide
38 // ================
39 //
40 //   To add track events to your application, first define your categories in,
41 //   e.g., my_tracing.h:
42 //
43 //       PERFETTO_DEFINE_CATEGORIES(
44 //           perfetto::Category("base"),
45 //           perfetto::Category("v8"),
46 //           perfetto::Category("cc"));
47 //
48 //   Then in a single .cc file, e.g., my_tracing.cc:
49 //
50 //       #include "my_tracing.h"
51 //       PERFETTO_TRACK_EVENT_STATIC_STORAGE();
52 //
53 //   Finally, register track events at startup, after which you can record
54 //   events with the TRACE_EVENT macros:
55 //
56 //       #include "my_tracing.h"
57 //
58 //       int main() {
59 //         perfetto::TrackEvent::Register();
60 //
61 //         // A basic track event with just a name.
62 //         TRACE_EVENT("category", "MyEvent");
63 //
64 //         // A track event with (up to two) debug annotations.
65 //         TRACE_EVENT("category", "MyEvent", "parameter", 42);
66 //
67 //         // A track event with a strongly typed parameter.
68 //         TRACE_EVENT("category", "MyEvent", [](perfetto::EventContext ctx) {
69 //           ctx.event()->set_foo(42);
70 //           ctx.event()->set_bar(.5f);
71 //         });
72 //       }
73 //
74 //  Note that track events must be nested consistently, i.e., the following is
75 //  not allowed:
76 //
77 //    TRACE_EVENT_BEGIN("a", "bar", ...);
78 //    TRACE_EVENT_BEGIN("b", "foo", ...);
79 //    TRACE_EVENT_END("a");  // "foo" must be closed before "bar".
80 //    TRACE_EVENT_END("b");
81 //
82 // ====================
83 // Implementation notes
84 // ====================
85 //
86 // The track event library consists of the following layers and components. The
87 // classes the internal namespace shouldn't be considered part of the public
88 // API.
89 //                    .--------------------------------.
90 //               .----|  TRACE_EVENT                   |----.
91 //      write   |     |   - App instrumentation point  |     |  write
92 //      event   |     '--------------------------------'     |  arguments
93 //              V                                            V
94 //  .----------------------------------.    .-----------------------------.
95 //  | TrackEvent                       |    | EventContext                |
96 //  |  - Registry of event categories  |    |  - One track event instance |
97 //  '----------------------------------'    '-----------------------------'
98 //              |                                            |
99 //              |                                            | look up
100 //              | is                                         | interning ids
101 //              V                                            V
102 //  .----------------------------------.    .-----------------------------.
103 //  | internal::TrackEventDataSource   |    | TrackEventInternedDataIndex |
104 //  | - Perfetto data source           |    | - Corresponds to a field in |
105 //  | - Has TrackEventIncrementalState |    |   in interned_data.proto    |
106 //  '----------------------------------'    '-----------------------------'
107 //              |                  |                         ^
108 //              |                  |       owns (1:many)     |
109 //              | write event      '-------------------------'
110 //              V
111 //  .----------------------------------.
112 //  | internal::TrackEventInternal     |
113 //  | - Outlined code to serialize     |
114 //  |   one track event                |
115 //  '----------------------------------'
116 //
117 
118 // Each compilation unit can be in exactly one track event namespace,
119 // allowing the overall program to use multiple track event data sources and
120 // category lists if necessary. Use this macro to select the namespace for the
121 // current compilation unit.
122 //
123 // If the program uses multiple track event namespaces, category & track event
124 // registration (see quickstart above) needs to happen for both namespaces
125 // separately.
126 #ifndef PERFETTO_TRACK_EVENT_NAMESPACE
127 #define PERFETTO_TRACK_EVENT_NAMESPACE perfetto
128 #endif
129 
130 // Deprecated; see perfetto::Category().
131 #define PERFETTO_CATEGORY(name) \
132   ::perfetto::Category { #name }
133 
134 // Internal helpers for determining if a given category is defined at build or
135 // runtime.
136 namespace PERFETTO_TRACK_EVENT_NAMESPACE {
137 namespace internal {
138 
139 // By default no statically defined categories are dynamic, but this can be
140 // overridden with PERFETTO_DEFINE_TEST_CATEGORY_PREFIXES.
141 template <typename... T>
IsDynamicCategory(const char *)142 constexpr bool IsDynamicCategory(const char*) {
143   return false;
144 }
145 
146 // Explicitly dynamic categories are always dynamic.
IsDynamicCategory(const::perfetto::DynamicCategory &)147 constexpr bool IsDynamicCategory(const ::perfetto::DynamicCategory&) {
148   return true;
149 }
150 
151 }  // namespace internal
152 }  // namespace PERFETTO_TRACK_EVENT_NAMESPACE
153 
154 namespace perfetto {
155 
156 // A wrapper for marking strings that can't be determined to be static at build
157 // time, but are in fact static.
158 class PERFETTO_EXPORT StaticString final {
159  public:
160   const char* value;
161 
162   operator const char*() const { return value; }
163 };
164 
165 namespace internal {
166 
167 template <typename T = void>
IsStaticString(const char *)168 constexpr bool IsStaticString(const char*) {
169   return true;
170 }
171 
172 template <typename T = void>
IsStaticString(...)173 constexpr bool IsStaticString(...) {
174   return false;
175 }
176 
177 }  // namespace internal
178 }  // namespace perfetto
179 
180 // Normally all categories are defined statically at build-time (see
181 // PERFETTO_DEFINE_CATEGORIES). However, some categories are only used for
182 // testing, and we shouldn't publish them to the tracing service or include them
183 // in a production binary. Use this macro to define a list of prefixes for these
184 // types of categories. Note that trace points using these categories will be
185 // slightly less efficient compared to regular trace points.
186 #define PERFETTO_DEFINE_TEST_CATEGORY_PREFIXES(...)                       \
187   namespace PERFETTO_TRACK_EVENT_NAMESPACE {                              \
188   namespace internal {                                                    \
189   template <>                                                             \
190   constexpr bool IsDynamicCategory(const char* name) {                    \
191     return ::perfetto::internal::IsStringInPrefixList(name, __VA_ARGS__); \
192   }                                                                       \
193   } /* namespace internal */                                              \
194   } /* namespace PERFETTO_TRACK_EVENT_NAMESPACE */                        \
195   PERFETTO_INTERNAL_SWALLOW_SEMICOLON()
196 
197 // Register the set of available categories by passing a list of categories to
198 // this macro: PERFETTO_CATEGORY(cat1), PERFETTO_CATEGORY(cat2), ...
199 #define PERFETTO_DEFINE_CATEGORIES(...)                        \
200   namespace PERFETTO_TRACK_EVENT_NAMESPACE {                   \
201   /* The list of category names */                             \
202   PERFETTO_INTERNAL_DECLARE_CATEGORIES(__VA_ARGS__)            \
203   /* The track event data source for this set of categories */ \
204   PERFETTO_INTERNAL_DECLARE_TRACK_EVENT_DATA_SOURCE();         \
205   } /* namespace PERFETTO_TRACK_EVENT_NAMESPACE */             \
206   PERFETTO_DECLARE_DATA_SOURCE_STATIC_MEMBERS(                 \
207       PERFETTO_TRACK_EVENT_NAMESPACE::TrackEvent,              \
208       perfetto::internal::TrackEventDataSourceTraits)
209 
210 // Allocate storage for each category by using this macro once per track event
211 // namespace.
212 #define PERFETTO_TRACK_EVENT_STATIC_STORAGE()      \
213   namespace PERFETTO_TRACK_EVENT_NAMESPACE {       \
214   PERFETTO_INTERNAL_CATEGORY_STORAGE()             \
215   } /* namespace PERFETTO_TRACK_EVENT_NAMESPACE */ \
216   PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(      \
217       PERFETTO_TRACK_EVENT_NAMESPACE::TrackEvent,  \
218       perfetto::internal::TrackEventDataSourceTraits)
219 
220 // Ignore GCC warning about a missing argument for a variadic macro parameter.
221 #pragma GCC system_header
222 
223 // Ensure that |string| is a static constant string.
224 //
225 // If you get a compiler failure here, you are most likely trying to use
226 // TRACE_EVENT with a dynamic event name. There are two ways to fix this:
227 //
228 // 1) If the event name is actually dynamic (e.g., std::string), write it into
229 //    the event manually:
230 //
231 //      TRACE_EVENT("category", nullptr, [&](perfetto::EventContext ctx) {
232 //        ctx.event()->set_name(dynamic_name);
233 //      });
234 //
235 // 2) If the name is static, but the pointer is computed at runtime, wrap it
236 //    with perfetto::StaticString:
237 //
238 //      TRACE_EVENT("category", perfetto::StaticString{name});
239 //
240 //    DANGER: Using perfetto::StaticString with strings whose contents change
241 //            dynamically can cause silent trace data corruption.
242 //
243 #define PERFETTO_GET_STATIC_STRING(string)                                 \
244   [&]() {                                                                  \
245     static_assert(                                                         \
246         std::is_same<decltype(string), ::perfetto::StaticString>::value || \
247             ::perfetto::internal::IsStaticString(string),                  \
248         "String must be static");                                          \
249     return static_cast<const char*>(string);                               \
250   }()
251 
252 // Begin a slice under |category| with the title |name|. Both strings must be
253 // static constants. The track event is only recorded if |category| is enabled
254 // for a tracing session.
255 //
256 // The slice is thread-scoped (i.e., written to the default track of the current
257 // thread) unless overridden with a custom track object (see Track).
258 //
259 // |name| must be a string with static lifetime (i.e., the same
260 // address must not be used for a different event name in the future). If you
261 // want to use a dynamically allocated name, do this:
262 //
263 //  TRACE_EVENT("category", nullptr, [&](perfetto::EventContext ctx) {
264 //    ctx.event()->set_name(dynamic_name);
265 //  });
266 //
267 #define TRACE_EVENT_BEGIN(category, name, ...)    \
268   PERFETTO_INTERNAL_TRACK_EVENT(                  \
269       category, PERFETTO_GET_STATIC_STRING(name), \
270       ::perfetto::protos::pbzero::TrackEvent::TYPE_SLICE_BEGIN, ##__VA_ARGS__)
271 
272 // End a slice under |category|.
273 #define TRACE_EVENT_END(category, ...) \
274   PERFETTO_INTERNAL_TRACK_EVENT(       \
275       category, nullptr,               \
276       ::perfetto::protos::pbzero::TrackEvent::TYPE_SLICE_END, ##__VA_ARGS__)
277 
278 // Begin a slice which gets automatically closed when going out of scope.
279 #define TRACE_EVENT(category, name, ...) \
280   PERFETTO_INTERNAL_SCOPED_TRACK_EVENT(category, name, ##__VA_ARGS__)
281 
282 // Emit a slice which has zero duration.
283 #define TRACE_EVENT_INSTANT(category, name, ...)  \
284   PERFETTO_INTERNAL_TRACK_EVENT(                  \
285       category, PERFETTO_GET_STATIC_STRING(name), \
286       ::perfetto::protos::pbzero::TrackEvent::TYPE_INSTANT, ##__VA_ARGS__)
287 
288 // Efficiently determine if the given static or dynamic trace category or
289 // category group is enabled for tracing.
290 #define TRACE_EVENT_CATEGORY_ENABLED(category) \
291   PERFETTO_INTERNAL_CATEGORY_ENABLED(category)
292 
293 // TODO(skyostil): Add flow events.
294 // TODO(skyostil): Add counters.
295 
296 #endif  // INCLUDE_PERFETTO_TRACING_TRACK_EVENT_H_
297