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/tracing/internal/track_event_data_source.h"
21 #include "perfetto/tracing/internal/track_event_internal.h"
22 #include "perfetto/tracing/internal/track_event_macros.h"
23 #include "perfetto/tracing/string_helpers.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 // DEPRECATED: Please use PERFETTO_DEFINE_CATEGORIES_IN_NAMESPACE to implement
119 // multiple track event category sets in one program.
120 //
121 // Each compilation unit can be in exactly one track event namespace,
122 // allowing the overall program to use multiple track event data sources and
123 // category lists if necessary. Use this macro to select the namespace for the
124 // current compilation unit.
125 //
126 // If the program uses multiple track event namespaces, category & track event
127 // registration (see quickstart above) needs to happen for both namespaces
128 // separately.
129
130 #ifndef PERFETTO_TRACK_EVENT_NAMESPACE
131 #define PERFETTO_TRACK_EVENT_NAMESPACE perfetto_track_event
132 #endif
133
134 // Deprecated; see perfetto::Category().
135 #define PERFETTO_CATEGORY(name) \
136 ::perfetto::Category { \
137 #name \
138 }
139
140 // Internal helpers for determining if a given category is defined at build or
141 // runtime.
142 namespace PERFETTO_TRACK_EVENT_NAMESPACE {
143 namespace internal {
144
145 // By default no statically defined categories are dynamic, but this can be
146 // overridden with PERFETTO_DEFINE_TEST_CATEGORY_PREFIXES.
147 template <typename... T>
IsDynamicCategory(const char *)148 constexpr bool IsDynamicCategory(const char*) {
149 return false;
150 }
151
152 // Explicitly dynamic categories are always dynamic.
IsDynamicCategory(const::perfetto::DynamicCategory &)153 constexpr bool IsDynamicCategory(const ::perfetto::DynamicCategory&) {
154 return true;
155 }
156
157 } // namespace internal
158 } // namespace PERFETTO_TRACK_EVENT_NAMESPACE
159
160 // Normally all categories are defined statically at build-time (see
161 // PERFETTO_DEFINE_CATEGORIES). However, some categories are only used for
162 // testing, and we shouldn't publish them to the tracing service or include them
163 // in a production binary. Use this macro to define a list of prefixes for these
164 // types of categories. Note that trace points using these categories will be
165 // slightly less efficient compared to regular trace points.
166 #define PERFETTO_DEFINE_TEST_CATEGORY_PREFIXES(...) \
167 namespace PERFETTO_TRACK_EVENT_NAMESPACE { \
168 namespace internal { \
169 template <> \
170 constexpr bool IsDynamicCategory(const char* name) { \
171 return ::perfetto::internal::IsStringInPrefixList(name, __VA_ARGS__); \
172 } \
173 } /* namespace internal */ \
174 } /* namespace PERFETTO_TRACK_EVENT_NAMESPACE */ \
175 PERFETTO_INTERNAL_SWALLOW_SEMICOLON()
176
177 // Register the set of available categories by passing a list of categories to
178 // this macro: perfetto::Category("cat1"), perfetto::Category("cat2"), ...
179 // `ns` is the name of the namespace in which the categories should be declared.
180 // `attrs` are linkage attributes for the underlying data source. See
181 // PERFETTO_DECLARE_DATA_SOURCE_STATIC_MEMBERS_WITH_ATTRS.
182 //
183 // Implementation note: the extra namespace (PERFETTO_TRACK_EVENT_NAMESPACE) is
184 // kept here only for backward compatibility.
185 #define PERFETTO_DEFINE_CATEGORIES_IN_NAMESPACE_WITH_ATTRS(ns, attrs, ...) \
186 namespace ns { \
187 namespace PERFETTO_TRACK_EVENT_NAMESPACE { \
188 /* The list of category names */ \
189 PERFETTO_INTERNAL_DECLARE_CATEGORIES(attrs, __VA_ARGS__) \
190 /* The track event data source for this set of categories */ \
191 PERFETTO_INTERNAL_DECLARE_TRACK_EVENT_DATA_SOURCE(attrs); \
192 } /* namespace PERFETTO_TRACK_EVENT_NAMESPACE */ \
193 using PERFETTO_TRACK_EVENT_NAMESPACE::TrackEvent; \
194 } /* namespace ns */ \
195 PERFETTO_DECLARE_DATA_SOURCE_STATIC_MEMBERS_WITH_ATTRS( \
196 attrs, ns::PERFETTO_TRACK_EVENT_NAMESPACE::TrackEvent, \
197 ::perfetto::internal::TrackEventDataSourceTraits)
198
199 // Register the set of available categories by passing a list of categories to
200 // this macro: perfetto::Category("cat1"), perfetto::Category("cat2"), ...
201 // `ns` is the name of the namespace in which the categories should be declared.
202 #define PERFETTO_DEFINE_CATEGORIES_IN_NAMESPACE(ns, ...) \
203 PERFETTO_DEFINE_CATEGORIES_IN_NAMESPACE_WITH_ATTRS( \
204 ns, PERFETTO_COMPONENT_EXPORT, __VA_ARGS__)
205
206 // Make categories in a given namespace the default ones used by track events
207 // for the current translation unit. Can only be used *once* in a given global
208 // or namespace scope.
209 #define PERFETTO_USE_CATEGORIES_FROM_NAMESPACE(ns) \
210 namespace PERFETTO_TRACK_EVENT_NAMESPACE { \
211 using ::ns::PERFETTO_TRACK_EVENT_NAMESPACE::TrackEvent; \
212 namespace internal { \
213 using ::ns::PERFETTO_TRACK_EVENT_NAMESPACE::internal::kCategoryRegistry; \
214 using ::ns::PERFETTO_TRACK_EVENT_NAMESPACE::internal:: \
215 kConstExprCategoryRegistry; \
216 } /* namespace internal */ \
217 } /* namespace PERFETTO_TRACK_EVENT_NAMESPACE */ \
218 PERFETTO_INTERNAL_SWALLOW_SEMICOLON()
219
220 // Make categories in a given namespace the default ones used by track events
221 // for the current block scope. Can only be used in a function or block scope.
222 #define PERFETTO_USE_CATEGORIES_FROM_NAMESPACE_SCOPED(ns) \
223 namespace PERFETTO_TRACK_EVENT_NAMESPACE = ns::PERFETTO_TRACK_EVENT_NAMESPACE
224
225 // Register categories in the default (global) namespace. Warning: only one set
226 // of global categories can be defined in a single program. Create namespaced
227 // categories with PERFETTO_DEFINE_CATEGORIES_IN_NAMESPACE to work around this
228 // limitation.
229 #define PERFETTO_DEFINE_CATEGORIES(...) \
230 PERFETTO_DEFINE_CATEGORIES_IN_NAMESPACE(perfetto, __VA_ARGS__); \
231 PERFETTO_USE_CATEGORIES_FROM_NAMESPACE(perfetto)
232
233 // Allocate storage for each category by using this macro once per track event
234 // namespace. `ns` is the name of the namespace in which the categories should
235 // be declared and `attrs` specify linkage attributes for the data source.
236 #define PERFETTO_TRACK_EVENT_STATIC_STORAGE_IN_NAMESPACE_WITH_ATTRS(ns, attrs) \
237 namespace ns { \
238 namespace PERFETTO_TRACK_EVENT_NAMESPACE { \
239 PERFETTO_INTERNAL_CATEGORY_STORAGE(attrs) \
240 PERFETTO_INTERNAL_DEFINE_TRACK_EVENT_DATA_SOURCE() \
241 } /* namespace PERFETTO_TRACK_EVENT_NAMESPACE */ \
242 } /* namespace ns */ \
243 PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS_WITH_ATTRS( \
244 attrs, ns::PERFETTO_TRACK_EVENT_NAMESPACE::TrackEvent, \
245 ::perfetto::internal::TrackEventDataSourceTraits)
246
247 // Allocate storage for each category by using this macro once per track event
248 // namespace.
249 #define PERFETTO_TRACK_EVENT_STATIC_STORAGE_IN_NAMESPACE(ns) \
250 PERFETTO_TRACK_EVENT_STATIC_STORAGE_IN_NAMESPACE_WITH_ATTRS( \
251 ns, PERFETTO_COMPONENT_EXPORT)
252
253 // Allocate storage for each category by using this macro once per track event
254 // namespace.
255 #define PERFETTO_TRACK_EVENT_STATIC_STORAGE() \
256 PERFETTO_TRACK_EVENT_STATIC_STORAGE_IN_NAMESPACE(perfetto)
257
258 #if defined(__GNUC__) || defined(__clang__)
259 #if defined(__clang__)
260 #pragma clang diagnostic push
261 // Fix 'error: #pragma system_header ignored in main file' for clang in Google3.
262 #pragma clang diagnostic ignored "-Wpragma-system-header-outside-header"
263 #endif
264
265 // Ignore GCC warning about a missing argument for a variadic macro parameter.
266 #pragma GCC system_header
267
268 #if defined(__clang__)
269 #pragma clang diagnostic pop
270 #endif
271 #endif
272
273 // Begin a slice under |category| with the title |name|. Both strings must be
274 // static constants. The track event is only recorded if |category| is enabled
275 // for a tracing session.
276 //
277 // The slice is thread-scoped (i.e., written to the default track of the current
278 // thread) unless overridden with a custom track object (see Track).
279 //
280 // |name| must be a string with static lifetime (i.e., the same
281 // address must not be used for a different event name in the future). If you
282 // want to use a dynamically allocated name, do this:
283 //
284 // TRACE_EVENT("category", nullptr, [&](perfetto::EventContext ctx) {
285 // ctx.event()->set_name(dynamic_name);
286 // });
287 //
288 // The following optional arguments can be passed to `TRACE_EVENT` to add extra
289 // information to events:
290 //
291 // TRACE_EVENT("cat", "name"[, track][, timestamp]
292 // [, "debug_name1", debug_value1]
293 // [, "debug_name2", debug_value2]
294 // ...
295 // [, "debug_nameN", debug_valueN]
296 // [, lambda]);
297 //
298 // Some examples of valid combinations:
299 //
300 // 1. A lambda for writing custom TrackEvent fields:
301 //
302 // TRACE_EVENT("category", "Name", [&](perfetto::EventContext ctx) {
303 // ctx.event()->set_custom_value(...);
304 // });
305 //
306 // 2. A timestamp and a lambda:
307 //
308 // TRACE_EVENT("category", "Name", time_in_nanoseconds,
309 // [&](perfetto::EventContext ctx) {
310 // ctx.event()->set_custom_value(...);
311 // });
312 //
313 // |time_in_nanoseconds| should be an uint64_t by default. To support custom
314 // timestamp types,
315 // |perfetto::TraceTimestampTraits<T>::ConvertTimestampToTraceTimeNs|
316 // should be defined. See |ConvertTimestampToTraceTimeNs| for more details.
317 //
318 // 3. Arbitrary number of debug annotations:
319 //
320 // TRACE_EVENT("category", "Name", "arg", value);
321 // TRACE_EVENT("category", "Name", "arg", value, "arg2", value2);
322 // TRACE_EVENT("category", "Name", "arg", value, "arg2", value2,
323 // "arg3", value3);
324 //
325 // See |TracedValue| for recording custom types as debug annotations.
326 //
327 // 4. Arbitrary number of debug annotations and a lambda:
328 //
329 // TRACE_EVENT("category", "Name", "arg", value,
330 // [&](perfetto::EventContext ctx) {
331 // ctx.event()->set_custom_value(...);
332 // });
333 //
334 // 5. An overridden track:
335 //
336 // TRACE_EVENT("category", "Name", perfetto::Track(1234));
337 //
338 // See |Track| for other types of tracks which may be used.
339 //
340 // 6. A track and a lambda:
341 //
342 // TRACE_EVENT("category", "Name", perfetto::Track(1234),
343 // [&](perfetto::EventContext ctx) {
344 // ctx.event()->set_custom_value(...);
345 // });
346 //
347 // 7. A track and a timestamp:
348 //
349 // TRACE_EVENT("category", "Name", perfetto::Track(1234),
350 // time_in_nanoseconds);
351 //
352 // 8. A track, a timestamp and a lambda:
353 //
354 // TRACE_EVENT("category", "Name", perfetto::Track(1234),
355 // time_in_nanoseconds, [&](perfetto::EventContext ctx) {
356 // ctx.event()->set_custom_value(...);
357 // });
358 //
359 // 9. A track and an arbitrary number of debug annotions:
360 //
361 // TRACE_EVENT("category", "Name", perfetto::Track(1234),
362 // "arg", value);
363 // TRACE_EVENT("category", "Name", perfetto::Track(1234),
364 // "arg", value, "arg2", value2);
365 //
366 #define TRACE_EVENT_BEGIN(category, name, ...) \
367 PERFETTO_INTERNAL_TRACK_EVENT_WITH_METHOD( \
368 TraceForCategory, category, name, \
369 ::perfetto::protos::pbzero::TrackEvent::TYPE_SLICE_BEGIN, ##__VA_ARGS__)
370
371 // End a slice under |category|.
372 #define TRACE_EVENT_END(category, ...) \
373 PERFETTO_INTERNAL_TRACK_EVENT_WITH_METHOD( \
374 TraceForCategory, category, /*name=*/nullptr, \
375 ::perfetto::protos::pbzero::TrackEvent::TYPE_SLICE_END, ##__VA_ARGS__)
376
377 // Begin a slice which gets automatically closed when going out of scope.
378 #define TRACE_EVENT(category, name, ...) \
379 PERFETTO_INTERNAL_SCOPED_TRACK_EVENT(category, name, ##__VA_ARGS__)
380
381 // Emit a slice which has zero duration.
382 #define TRACE_EVENT_INSTANT(category, name, ...) \
383 PERFETTO_INTERNAL_TRACK_EVENT_WITH_METHOD( \
384 TraceForCategory, category, name, \
385 ::perfetto::protos::pbzero::TrackEvent::TYPE_INSTANT, ##__VA_ARGS__)
386
387 // Efficiently determine if the given static or dynamic trace category or
388 // category group is enabled for tracing.
389 #define TRACE_EVENT_CATEGORY_ENABLED(category) \
390 PERFETTO_INTERNAL_CATEGORY_ENABLED(category)
391
392 // Time-varying numeric data can be recorded with the TRACE_COUNTER macro:
393 //
394 // TRACE_COUNTER("cat", counter_track[, timestamp], value);
395 //
396 // For example, to record a single value for a counter called "MyCounter":
397 //
398 // TRACE_COUNTER("category", "MyCounter", 1234.5);
399 //
400 // This data is displayed as a counter track in the Perfetto UI.
401 //
402 // Both integer and floating point counter values are supported. Counters can
403 // also be annotated with additional information such as units, for example, for
404 // tracking the rendering framerate in terms of frames per second or "fps":
405 //
406 // TRACE_COUNTER("category", perfetto::CounterTrack("Framerate", "fps"), 120);
407 //
408 // As another example, a memory counter that records bytes but accepts samples
409 // as kilobytes (to reduce trace binary size) can be defined like this:
410 //
411 // perfetto::CounterTrack memory_track = perfetto::CounterTrack("Memory")
412 // .set_unit("bytes")
413 // .set_multiplier(1024);
414 // TRACE_COUNTER("category", memory_track, 4 /* = 4096 bytes */);
415 //
416 // See /protos/perfetto/trace/track_event/counter_descriptor.proto
417 // for the full set of attributes for a counter track.
418 //
419 // To record a counter value at a specific point in time (instead of the current
420 // time), you can pass in a custom timestamp:
421 //
422 // // First record the current time and counter value.
423 // uint64_t timestamp = perfetto::TrackEvent::GetTraceTimeNs();
424 // int64_t value = 1234;
425 //
426 // // Later, emit a sample at that point in time.
427 // TRACE_COUNTER("category", "MyCounter", timestamp, value);
428 //
429 #define TRACE_COUNTER(category, track, ...) \
430 PERFETTO_INTERNAL_TRACK_EVENT_WITH_METHOD( \
431 TraceForCategory, category, /*name=*/nullptr, \
432 ::perfetto::protos::pbzero::TrackEvent::TYPE_COUNTER, \
433 ::perfetto::CounterTrack(track), ##__VA_ARGS__)
434
435 // TODO(skyostil): Add flow events.
436
437 #endif // INCLUDE_PERFETTO_TRACING_TRACK_EVENT_H_
438