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