• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Track events (Tracing SDK)
2
3Track events are part of the [Perfetto Tracing SDK](tracing-sdk.md).
4
5*Track events* are application specific, time bounded events recorded into a
6*trace* while the application is running. Track events are always associated
7with a *track*, which is a timeline of monotonically increasing time. A track
8corresponds to an independent sequence of execution, such as a single thread
9in a process.
10
11![Track events shown in the Perfetto UI](
12  /docs/images/track-events.png "Track events in the Perfetto UI")
13
14See the [Getting started](/docs/instrumentation/tracing-sdk#getting-started)
15section of the Tracing SDK page for instructions on how to check out and
16build the SDK.
17
18TIP: The code from these examples is also available [in the
19repository](/examples/sdk/README.md).
20
21There are a few main types of track events:
22
23- **Slices**, which represent nested, time bounded operations. For example,
24    a slice could cover the time period from when a function begins executing
25    to when it returns, the time spent loading a file from the network or the
26    time to complete a user journey.
27
28- **Counters**, which are snapshots of time-varying numeric values. For
29    example, a track event can record instantaneous the memory usage of a
30    process during its execution.
31
32- **Flows**, which are used to connect related slices that span different
33    tracks together. For example, if an image file is first loaded from
34    the network and then decoded on a thread pool, a flow event can be used to
35    highlight its path through the system. (Not fully implemented yet).
36
37The [Perfetto UI](https://ui.perfetto.dev) has built in support for track
38events, which provides a useful way to quickly visualize the internal
39processing of an app. For example, the [Chrome
40browser](https://www.chromium.org/developers/how-tos/trace-event-profiling-tool)
41is deeply instrumented with track events to assist in debugging, development
42and performance analysis.
43
44To start using track events, first define the set of categories that your events
45will fall into. Each category can be separately enabled or disabled for tracing
46(see [Category configuration](#category-configuration)).
47
48Add the list of categories into a header file (e.g.,
49`my_app_tracing_categories.h`) like this:
50
51```C++
52#include <perfetto.h>
53
54PERFETTO_DEFINE_CATEGORIES(
55    perfetto::Category("rendering")
56        .SetDescription("Events from the graphics subsystem"),
57    perfetto::Category("network")
58        .SetDescription("Network upload and download statistics"));
59```
60
61Then, declare static storage for the categories in a cc file (e.g.,
62`my_app_tracing_categories.cc`):
63
64```C++
65#include "my_app_tracing_categories.h"
66
67PERFETTO_TRACK_EVENT_STATIC_STORAGE();
68```
69
70Finally, initialize track events after the client library is brought up:
71
72```C++
73int main(int argv, char** argc) {
74  ...
75  perfetto::Tracing::Initialize(args);
76  perfetto::TrackEvent::Register();  // Add this.
77}
78```
79
80Now you can add track events to existing functions like this:
81
82```C++
83#include "my_app_tracing_categories.h"
84
85void DrawPlayer() {
86  TRACE_EVENT("rendering", "DrawPlayer");  // Begin "DrawPlayer" slice.
87  ...
88  // End "DrawPlayer" slice.
89}
90```
91
92This type of trace event is scoped, under the hood it uses C++ [RAII]. The
93event will cover the time from when the `TRACE_EVENT` annotation is encountered
94to the end of the block (in the example above, until the function returns).
95
96For events that don't follow function scoping, use `TRACE_EVENT_BEGIN` and
97`TRACE_EVENT_END`:
98
99```C++
100void LoadGame() {
101  DisplayLoadingScreen();
102
103  TRACE_EVENT_BEGIN("io", "Loading");  // Begin "Loading" slice.
104  LoadCollectibles();
105  LoadVehicles();
106  LoadPlayers();
107  TRACE_EVENT_END("io");               // End "Loading" slice.
108
109  StartGame();
110}
111```
112
113Note that you don't need to give a name for `TRACE_EVENT_END`, since it
114automatically closes the most recent event that began on the same thread. In
115other words, all events on a given thread share the same stack. This means
116that it's not recommended to have a matching pair of `TRACE_EVENT_BEGIN` and
117`TRACE_EVENT_END` markers in separate functions, since an unrelated event
118might terminate the original event unexpectedly; for events that cross
119function boundaries it's usually best to emit them on a [separate
120track](#tracks).
121
122You can also supply (up to two) debug annotations together with the event.
123
124```C++
125int player_number = 1;
126TRACE_EVENT("rendering", "DrawPlayer", "player_number", player_number);
127```
128
129See [below](#track-event-arguments) for the other types of supported track
130event arguments. For more complex arguments, you can define [your own
131protobuf messages](/protos/perfetto/trace/track_event/track_event.proto) and
132emit them as a parameter for the event.
133
134NOTE: Currently custom protobuf messages need to be added directly to the
135      Perfetto repository under `protos/perfetto/trace`, and Perfetto itself
136      must also be rebuilt. We are working
137      [to lift this limitation](https://github.com/google/perfetto/issues/11).
138
139As an example of a custom track event argument type, save the following as
140`protos/perfetto/trace/track_event/player_info.proto`:
141
142```protobuf
143message PlayerInfo {
144  optional string name = 1;
145  optional uint64 score = 2;
146}
147```
148
149This new file should also be added to
150`protos/perfetto/trace/track_event/BUILD.gn`:
151
152```json
153sources = [
154  ...
155  "player_info.proto"
156]
157```
158
159Also, a matching argument should be added to the track event message
160definition in
161`protos/perfetto/trace/track_event/track_event.proto`:
162
163```protobuf
164import "protos/perfetto/trace/track_event/player_info.proto";
165
166...
167
168message TrackEvent {
169  ...
170  // New argument types go here.
171  optional PlayerInfo player_info = 1000;
172}
173```
174
175The corresponding trace point could look like this:
176
177```C++
178Player my_player;
179TRACE_EVENT("category", "MyEvent", [&](perfetto::EventContext ctx) {
180  auto player = ctx.event()->set_player_info();
181  player->set_name(my_player.name());
182  player->set_player_score(my_player.score());
183});
184```
185
186The lambda function passed to the macro is only called if tracing is enabled for
187the given category. It is always called synchronously and possibly multiple
188times if multiple concurrent tracing sessions are active.
189
190Now that you have instrumented your app with track events, you are ready to
191start [recording traces](tracing-sdk.md#recording).
192
193## Category configuration
194
195All track events are assigned to one more trace categories. For example:
196
197```C++
198TRACE_EVENT("rendering", ...);  // Event in the "rendering" category.
199```
200
201By default, all non-debug and non-slow track event categories are enabled for
202tracing. *Debug* and *slow* categories are categories with special tags:
203
204  - `"debug"` categories can give more verbose debugging output for a particular
205    subsystem.
206  - `"slow"` categories record enough data that they can affect the interactive
207    performance of your app.
208
209Category tags can be can be defined like this:
210
211```C++
212perfetto::Category("rendering.debug")
213    .SetDescription("Debug events from the graphics subsystem")
214    .SetTags("debug", "my_custom_tag")
215```
216
217A single trace event can also belong to multiple categories:
218
219```C++
220// Event in the "rendering" and "benchmark" categories.
221TRACE_EVENT("rendering,benchmark", ...);
222```
223
224A corresponding category group entry must be added to the category registry:
225
226```C++
227perfetto::Category::Group("rendering,benchmark")
228```
229
230It's also possible to efficiently query whether a given category is enabled
231for tracing:
232
233```C++
234if (TRACE_EVENT_CATEGORY_ENABLED("rendering")) {
235  // ...
236}
237```
238
239The `TrackEventConfig` field in Perfetto's `TraceConfig` can be used to
240select which categories are enabled for tracing:
241
242```protobuf
243message TrackEventConfig {
244  // Each list item is a glob. Each category is matched against the lists
245  // as explained below.
246  repeated string disabled_categories = 1;  // Default: []
247  repeated string enabled_categories = 2;   // Default: []
248  repeated string disabled_tags = 3;        // Default: [“slow”, “debug”]
249  repeated string enabled_tags = 4;         // Default: []
250}
251```
252
253To determine if a category is enabled, it is checked against the filters in the
254following order:
255
2561. Exact matches in enabled categories.
2572. Exact matches in enabled tags.
2583. Exact matches in disabled categories.
2594. Exact matches in disabled tags.
2605. Pattern matches in enabled categories.
2616. Pattern matches in enabled tags.
2627. Pattern matches in disabled categories.
2638. Pattern matches in disabled tags.
264
265If none of the steps produced a match, the category is enabled by default. In
266other words, every category is implicitly enabled unless specifically disabled.
267For example:
268
269| Setting                         | Needed configuration                         |
270| ------------------------------- | -------------------------------------------- |
271| Enable just specific categories | `enabled_categories = [“foo”, “bar”, “baz”]` |
272|                                 | `disabled_categories = [“*”]`                |
273| Enable all non-slow categories  | (Happens by default.)                        |
274| Enable specific tags            | `disabled_tags = [“*”]`                      |
275|                                 | `enabled_tags = [“foo”, “bar”]`              |
276
277## Dynamic and test-only categories
278
279Ideally all trace categories should be defined at compile time as shown
280above, as this ensures trace points will have minimal runtime and binary size
281overhead. However, in some cases trace categories can only be determined at
282runtime (e.g., they come from instrumentation in a dynamically loaded JavaScript
283running in a WebView or in a NodeJS engine). These can be used by trace points
284as follows:
285
286```C++
287perfetto::DynamicCategory dynamic_category{"nodejs.something"};
288TRACE_EVENT(dynamic_category, "SomeEvent", ...);
289```
290
291TIP: It's also possible to use dynamic event names by passing `nullptr` as
292    the name and filling in the `TrackEvent::name` field manually.
293
294Some trace categories are only useful for testing, and they should not make
295it into a production binary. These types of categories can be defined with a
296list of prefix strings:
297
298```C++
299PERFETTO_DEFINE_TEST_CATEGORY_PREFIXES(
300   "test",      // Applies to test.*
301   "dontship"   // Applies to dontship.*.
302);
303```
304
305## Performance
306
307Perfetto's trace points are designed to have minimal overhead when tracing is
308disabled while providing high throughput for data intensive tracing use
309cases. While exact timings will depend on your system, there is a
310[microbenchmark](/src/tracing/api_benchmark.cc) which gives some ballpark
311figures:
312
313| Scenario | Runtime on Pixel 3 XL | Runtime on ThinkStation P920 |
314| -------- | --------------------- | ---------------------------- |
315| `TRACE_EVENT(...)` (disabled)              | 2 ns   | 1 ns   |
316| `TRACE_EVENT("cat", "name")`               | 285 ns | 630 ns |
317| `TRACE_EVENT("cat", "name", <lambda>)`     | 304 ns | 663 ns |
318| `TRACE_EVENT("cat", "name", "key", value)` | 354 ns | 664 ns |
319| `DataSource::Trace(<lambda>)` (disabled)   | 2 ns   | 1 ns   |
320| `DataSource::Trace(<lambda>)`              | 133 ns | 58 ns  |
321
322## Advanced topics
323
324### Track event arguments
325
326The following optional arguments can be passed to `TRACE_EVENT` to add extra
327information to events:
328
329```C++
330TRACE_EVENT("cat", "name"[, track][, timestamp]
331    (, "debug_name", debug_value |, TrackEvent::kFieldName, value)*
332    [, lambda]);
333```
334
335Some examples of valid combinations:
336
3371. A lambda for writing custom TrackEvent fields:
338
339   ```C++
340     TRACE_EVENT("category", "Name", [&](perfetto::EventContext ctx) {
341       ctx.event()->set_custom_value(...);
342     });
343   ```
344
3452. A timestamp and a lambda:
346
347   ```C++
348     TRACE_EVENT("category", "Name", time_in_nanoseconds,
349         [&](perfetto::EventContext ctx) {
350       ctx.event()->set_custom_value(...);
351     });
352   ```
353
354   |time_in_nanoseconds| should be an uint64_t by default. To support custom
355   timestamp types,
356   |perfetto::TraceTimestampTraits<MyTimestamp>::ConvertTimestampToTraceTimeNs|
357   should be defined. See |ConvertTimestampToTraceTimeNs| for more details.
358
3593. Arbitrary number of debug annotations:
360
361   ```C++
362     TRACE_EVENT("category", "Name", "arg", value);
363     TRACE_EVENT("category", "Name", "arg", value, "arg2", value2);
364     TRACE_EVENT("category", "Name", "arg", value, "arg2", value2,
365                 "arg3", value3);
366   ```
367
368   See |TracedValue| for recording custom types as debug annotations.
369
3704. Arbitrary number of TrackEvent fields (including extensions):
371
372  ```C++
373    TRACE_EVENT("category", "Name",
374                perfetto::protos::pbzero::TrackEvent::kFieldName, value);
375  ```
376
3775. Arbitrary combination of debug annotations and TrackEvent fields:
378
379  ```C++
380    TRACE_EVENT("category", "Name",
381                perfetto::protos::pbzero::TrackEvent::kFieldName, value1,
382                "arg", value2);
383  ```
384
3856. Arbitrary combination of debug annotations / TrackEvent fields and a lambda:
386
387   ```C++
388     TRACE_EVENT("category", "Name", "arg", value1,
389                 pbzero::TrackEvent::kFieldName, value2,
390                 [&](perfetto::EventContext ctx) {
391                     ctx.event()->set_custom_value(...);
392                 });
393   ```
394
3957. An overridden track:
396
397   ```C++
398     TRACE_EVENT("category", "Name", perfetto::Track(1234));
399   ```
400
401   See |Track| for other types of tracks which may be used.
402
4038. A track and a lambda:
404
405   ```C++
406     TRACE_EVENT("category", "Name", perfetto::Track(1234),
407                 [&](perfetto::EventContext ctx) {
408                     ctx.event()->set_custom_value(...);
409                 });
410   ```
411
4129. A track and a timestamp:
413
414   ```C++
415     TRACE_EVENT("category", "Name", perfetto::Track(1234),
416                 time_in_nanoseconds);
417   ```
418
41910. A track, a timestamp and a lambda:
420
421   ```C++
422     TRACE_EVENT("category", "Name", perfetto::Track(1234),
423                 time_in_nanoseconds, [&](perfetto::EventContext ctx) {
424                     ctx.event()->set_custom_value(...);
425                 });
426   ```
427
42811. A track and any combination of debug annotions and TrackEvent fields:
429
430   ```C++
431     TRACE_EVENT("category", "Name", perfetto::Track(1234),
432                 "arg", value);
433     TRACE_EVENT("category", "Name", perfetto::Track(1234),
434                 "arg", value, "arg2", value2);
435     TRACE_EVENT("category", "Name", perfetto::Track(1234),
436                 "arg", value, "arg2", value2,
437                 pbzero::TrackEvent::kFieldName, value3);
438   ```
439
440### Tracks
441
442Every track event is associated with a track, which specifies the timeline
443the event belongs to. In most cases, a track corresponds to a visual
444horizontal track in the Perfetto UI like this:
445
446![Track timelines shown in the Perfetto UI](
447  /docs/images/track-timeline.png "Track timelines in the Perfetto UI")
448
449Events that describe parallel sequences (e.g., separate
450threads) should use separate tracks, while sequential events (e.g., nested
451function calls) generally belong on the same track.
452
453Perfetto supports three kinds of tracks:
454
455- `Track` – a basic timeline.
456
457- `ProcessTrack` – a timeline that represents a single process in the system.
458
459- `ThreadTrack` – a timeline that represents a single thread in the system.
460
461Tracks can have a parent track, which is used to group related tracks
462together. For example, the parent of a `ThreadTrack` is the `ProcessTrack` of
463the process the thread belongs to. By default, tracks are grouped under the
464current process's `ProcessTrack`.
465
466A track is identified by a uuid, which must be unique across the entire
467recorded trace. To minimize the chances of accidental collisions, the uuids
468of child tracks are combined with those of their parents, with each
469`ProcessTrack` having a random, per-process uuid.
470
471By default, track events (e.g., `TRACE_EVENT`) use the `ThreadTrack` for the
472calling thread. This can be overridden, for example, to mark events that
473begin and end on a different thread:
474
475```C++
476void OnNewRequest(size_t request_id) {
477  // Open a slice when the request came in.
478  TRACE_EVENT_BEGIN("category", "HandleRequest", perfetto::Track(request_id));
479
480  // Start a thread to handle the request.
481  std::thread worker_thread([=] {
482    // ... produce response ...
483
484    // Close the slice for the request now that we finished handling it.
485    TRACE_EVENT_END("category", perfetto::Track(request_id));
486  });
487```
488Tracks can also optionally be annotated with metadata:
489
490```C++
491auto desc = track.Serialize();
492desc.set_name("MyTrack");
493perfetto::TrackEvent::SetTrackDescriptor(track, desc);
494```
495
496Threads and processes can also be named in a similar way, e.g.:
497
498```C++
499auto desc = perfetto::ProcessTrack::Current().Serialize();
500desc.mutable_process()->set_process_name("MyProcess");
501perfetto::TrackEvent::SetTrackDescriptor(
502    perfetto::ProcessTrack::Current(), desc);
503```
504
505The metadata remains valid between tracing sessions. To free up data for a
506track, call EraseTrackDescriptor:
507
508```C++
509perfetto::TrackEvent::EraseTrackDescriptor(track);
510```
511
512### Counters
513
514Time-varying numeric data can be recorded with the `TRACE_COUNTER` macro:
515
516```C++
517TRACE_COUNTER("category", "MyCounter", 1234.5);
518```
519
520This data is displayed as a counter track in the Perfetto UI:
521
522![A counter track shown in the Perfetto UI](
523  /docs/images/counter-events.png "A counter track shown in the Perfetto UI")
524
525Both integer and floating point counter values are supported. Counters can
526also be annotated with additional information such as units, for example, for
527tracking the rendering framerate in terms of frames per second or "fps":
528
529```C++
530TRACE_COUNTER("category", perfetto::CounterTrack("Framerate", "fps"), 120);
531```
532
533As another example, a memory counter that records bytes but accepts samples
534as kilobytes (to reduce trace binary size) can be defined like this:
535
536```C++
537perfetto::CounterTrack memory_track = perfetto::CounterTrack("Memory")
538    .set_unit("bytes")
539    .set_multiplier(1024);
540TRACE_COUNTER("category", memory_track, 4 /* = 4096 bytes */);
541```
542
543See
544[counter_descriptor.proto](
545/protos/perfetto/trace/track_event/counter_descriptor.proto) for the full set
546of attributes for a counter track.
547
548To record a counter value at a specific point in time (instead of the current
549time), you can pass in a custom timestamp:
550
551```C++
552// First record the current time and counter value.
553uint64_t timestamp = perfetto::TrackEvent::GetTraceTimeNs();
554int64_t value = 1234;
555
556// Later, emit a sample at that point in time.
557TRACE_COUNTER("category", "MyCounter", timestamp, value);
558```
559
560### Interning
561
562Interning can be used to avoid repeating the same constant data (e.g., event
563names) throughout the trace. Perfetto automatically performs interning for
564most strings passed to `TRACE_EVENT`, but it's also possible to also define
565your own types of interned data.
566
567First, define an interning index for your type. It should map to a specific
568field of
569[interned_data.proto](/protos/perfetto/trace/interned_data/interned_data.proto)
570and specify how the interned data is written into that message when seen for
571the first time.
572
573```C++
574struct MyInternedData
575    : public perfetto::TrackEventInternedDataIndex<
576        MyInternedData,
577        perfetto::protos::pbzero::InternedData::kMyInternedDataFieldNumber,
578        const char*> {
579  static void Add(perfetto::protos::pbzero::InternedData* interned_data,
580                   size_t iid,
581                   const char* value) {
582    auto my_data = interned_data->add_my_interned_data();
583    my_data->set_iid(iid);
584    my_data->set_value(value);
585  }
586};
587```
588
589Next, use your interned data in a trace point as shown below. The interned
590string will only be emitted the first time the trace point is hit (unless the
591trace buffer has wrapped around).
592
593```C++
594TRACE_EVENT(
595   "category", "Event", [&](perfetto::EventContext ctx) {
596     auto my_message = ctx.event()->set_my_message();
597     size_t iid = MyInternedData::Get(&ctx, "Repeated data to be interned");
598     my_message->set_iid(iid);
599   });
600```
601
602Note that interned data is strongly typed, i.e., each class of interned data
603uses a separate namespace for identifiers.
604
605### Tracing session observers
606
607The session observer interface allows applications to be notified when track
608event tracing starts and stops:
609
610```C++
611class Observer : public perfetto::TrackEventSessionObserver {
612  public:
613  ~Observer() override = default;
614
615  void OnSetup(const perfetto::DataSourceBase::SetupArgs&) override {
616    // Called when tracing session is configured. Note tracing isn't active yet,
617    // so track events emitted here won't be recorded.
618  }
619
620  void OnStart(const perfetto::DataSourceBase::StartArgs&) override {
621    // Called when a tracing session is started. It is possible to emit track
622    // events from this callback.
623  }
624
625  void OnStop(const perfetto::DataSourceBase::StopArgs&) override {
626    // Called when a tracing session is stopped. It is still possible to emit
627    // track events from this callback.
628  }
629};
630```
631
632Note that all methods of the interface are called on an internal Perfetto
633thread.
634
635For example, here's how to wait for any tracing session to start:
636
637```C++
638class Observer : public perfetto::TrackEventSessionObserver {
639 public:
640  Observer() { perfetto::TrackEvent::AddSessionObserver(this); }
641  ~Observer() { perfetto::TrackEvent::RemoveSessionObserver(this); }
642
643  void OnStart(const perfetto::DataSourceBase::StartArgs&) override {
644    std::unique_lock<std::mutex> lock(mutex);
645    cv.notify_one();
646  }
647
648  void WaitForTracingStart() {
649    printf("Waiting for tracing to start...\n");
650    std::unique_lock<std::mutex> lock(mutex);
651    cv.wait(lock, [] { return perfetto::TrackEvent::IsEnabled(); });
652    printf("Tracing started\n");
653  }
654
655  std::mutex mutex;
656  std::condition_variable cv;
657};
658
659Observer observer;
660observer.WaitForTracingToStart();
661```
662
663[RAII]: https://en.cppreference.com/w/cpp/language/raii
664