• 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 argc, char** argv) {
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 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_BEGIN(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## Dynamic event names
306
307Ideally all event name should be compile time string constants. For example:
308
309```C++
310TRACE_EVENT_BEGIN("rendering", "DrawGame");
311```
312
313Here `"DrawGame"` is a compile time string. If we pass a dynamic string here,
314we will get compile time static_assert failure. For example :
315
316```C++
317const char* name = "DrawGame";
318TRACE_EVENT_BEGIN("rendering", name);  // Error. Event name is not static.
319```
320
321There are two ways to use dynamic event name:
322
3231) If the event name is actually dynamic (e.g., std::string), write it using
324   `perfetto::DynamicString`:
325
326```C++
327  TRACE_EVENT("category", perfetto::DynamicString{dynamic_name});
328```
329
330Note: Below is the old way of using dynamic event names. It's not recommended
331      anymore.
332
333```C++
334TRACE_EVENT("category", nullptr, [&](perfetto::EventContext ctx) {
335  ctx.event()->set_name(dynamic_name);
336});
337```
338
3392) If the name is static, but the pointer is computed at runtime, wrap it
340   with perfetto::StaticString:
341
342```C++
343TRACE_EVENT("category", perfetto::StaticString{name});
344TRACE_EVENT("category", perfetto::StaticString{i % 2 == 0 ? "A" : "B"});
345```
346
347DANGER: Using perfetto::StaticString with strings whose contents change
348        dynamically can cause silent trace data corruption.
349
350## Performance
351
352Perfetto's trace points are designed to have minimal overhead when tracing is
353disabled while providing high throughput for data intensive tracing use
354cases. While exact timings will depend on your system, there is a
355[microbenchmark](/src/tracing/api_benchmark.cc) which gives some ballpark
356figures:
357
358| Scenario | Runtime on Pixel 3 XL | Runtime on ThinkStation P920 |
359| -------- | --------------------- | ---------------------------- |
360| `TRACE_EVENT(...)` (disabled)              | 2 ns   | 1 ns   |
361| `TRACE_EVENT("cat", "name")`               | 285 ns | 630 ns |
362| `TRACE_EVENT("cat", "name", <lambda>)`     | 304 ns | 663 ns |
363| `TRACE_EVENT("cat", "name", "key", value)` | 354 ns | 664 ns |
364| `DataSource::Trace(<lambda>)` (disabled)   | 2 ns   | 1 ns   |
365| `DataSource::Trace(<lambda>)`              | 133 ns | 58 ns  |
366
367## Advanced topics
368
369### Track event arguments
370
371The following optional arguments can be passed to `TRACE_EVENT` to add extra
372information to events:
373
374```C++
375TRACE_EVENT("cat", "name"[, track][, timestamp]
376    (, "debug_name", debug_value |, TrackEvent::kFieldName, value)*
377    [, lambda]);
378```
379
380Some examples of valid combinations:
381
3821. A lambda for writing custom TrackEvent fields:
383
384   ```C++
385     TRACE_EVENT("category", "Name", [&](perfetto::EventContext ctx) {
386       ctx.event()->set_custom_value(...);
387     });
388   ```
389
3902. A timestamp and a lambda:
391
392   ```C++
393     TRACE_EVENT("category", "Name", time_in_nanoseconds,
394         [&](perfetto::EventContext ctx) {
395       ctx.event()->set_custom_value(...);
396     });
397   ```
398
399   |time_in_nanoseconds| should be an uint64_t by default. To support custom
400   timestamp types,
401   |perfetto::TraceTimestampTraits<MyTimestamp>::ConvertTimestampToTraceTimeNs|
402   should be defined. See |ConvertTimestampToTraceTimeNs| for more details.
403
4043. Arbitrary number of debug annotations:
405
406   ```C++
407     TRACE_EVENT("category", "Name", "arg", value);
408     TRACE_EVENT("category", "Name", "arg", value, "arg2", value2);
409     TRACE_EVENT("category", "Name", "arg", value, "arg2", value2,
410                 "arg3", value3);
411   ```
412
413   See |TracedValue| for recording custom types as debug annotations.
414
4154. Arbitrary number of TrackEvent fields (including extensions):
416
417  ```C++
418    TRACE_EVENT("category", "Name",
419                perfetto::protos::pbzero::TrackEvent::kFieldName, value);
420  ```
421
4225. Arbitrary combination of debug annotations and TrackEvent fields:
423
424  ```C++
425    TRACE_EVENT("category", "Name",
426                perfetto::protos::pbzero::TrackEvent::kFieldName, value1,
427                "arg", value2);
428  ```
429
4306. Arbitrary combination of debug annotations / TrackEvent fields and a lambda:
431
432   ```C++
433     TRACE_EVENT("category", "Name", "arg", value1,
434                 pbzero::TrackEvent::kFieldName, value2,
435                 [&](perfetto::EventContext ctx) {
436                     ctx.event()->set_custom_value(...);
437                 });
438   ```
439
4407. An overridden track:
441
442   ```C++
443     TRACE_EVENT("category", "Name", perfetto::Track(1234));
444   ```
445
446   See |Track| for other types of tracks which may be used.
447
4488. A track and a lambda:
449
450   ```C++
451     TRACE_EVENT("category", "Name", perfetto::Track(1234),
452                 [&](perfetto::EventContext ctx) {
453                     ctx.event()->set_custom_value(...);
454                 });
455   ```
456
4579. A track and a timestamp:
458
459   ```C++
460     TRACE_EVENT("category", "Name", perfetto::Track(1234),
461                 time_in_nanoseconds);
462   ```
463
46410. A track, a timestamp and a lambda:
465
466   ```C++
467     TRACE_EVENT("category", "Name", perfetto::Track(1234),
468                 time_in_nanoseconds, [&](perfetto::EventContext ctx) {
469                     ctx.event()->set_custom_value(...);
470                 });
471   ```
472
47311. A track and any combination of debug annotions and TrackEvent fields:
474
475   ```C++
476     TRACE_EVENT("category", "Name", perfetto::Track(1234),
477                 "arg", value);
478     TRACE_EVENT("category", "Name", perfetto::Track(1234),
479                 "arg", value, "arg2", value2);
480     TRACE_EVENT("category", "Name", perfetto::Track(1234),
481                 "arg", value, "arg2", value2,
482                 pbzero::TrackEvent::kFieldName, value3);
483   ```
484
485### Tracks
486
487Every track event is associated with a track, which specifies the timeline
488the event belongs to. In most cases, a track corresponds to a visual
489horizontal track in the Perfetto UI like this:
490
491![Track timelines shown in the Perfetto UI](
492  /docs/images/track-timeline.png "Track timelines in the Perfetto UI")
493
494Events that describe parallel sequences (e.g., separate
495threads) should use separate tracks, while sequential events (e.g., nested
496function calls) generally belong on the same track.
497
498Perfetto supports three kinds of tracks:
499
500- `Track` – a basic timeline.
501
502- `ProcessTrack` – a timeline that represents a single process in the system.
503
504- `ThreadTrack` – a timeline that represents a single thread in the system.
505
506Tracks can have a parent track, which is used to group related tracks
507together. For example, the parent of a `ThreadTrack` is the `ProcessTrack` of
508the process the thread belongs to. By default, tracks are grouped under the
509current process's `ProcessTrack`.
510
511A track is identified by a uuid, which must be unique across the entire
512recorded trace. To minimize the chances of accidental collisions, the uuids
513of child tracks are combined with those of their parents, with each
514`ProcessTrack` having a random, per-process uuid.
515
516By default, track events (e.g., `TRACE_EVENT`) use the `ThreadTrack` for the
517calling thread. This can be overridden, for example, to mark events that
518begin and end on a different thread:
519
520```C++
521void OnNewRequest(size_t request_id) {
522  // Open a slice when the request came in.
523  TRACE_EVENT_BEGIN("category", "HandleRequest", perfetto::Track(request_id));
524
525  // Start a thread to handle the request.
526  std::thread worker_thread([=] {
527    // ... produce response ...
528
529    // Close the slice for the request now that we finished handling it.
530    TRACE_EVENT_END("category", perfetto::Track(request_id));
531  });
532```
533Tracks can also optionally be annotated with metadata:
534
535```C++
536auto desc = track.Serialize();
537desc.set_name("MyTrack");
538perfetto::TrackEvent::SetTrackDescriptor(track, desc);
539```
540
541Threads and processes can also be named in a similar way, e.g.:
542
543```C++
544auto desc = perfetto::ProcessTrack::Current().Serialize();
545desc.mutable_process()->set_process_name("MyProcess");
546perfetto::TrackEvent::SetTrackDescriptor(
547    perfetto::ProcessTrack::Current(), desc);
548```
549
550The metadata remains valid between tracing sessions. To free up data for a
551track, call EraseTrackDescriptor:
552
553```C++
554perfetto::TrackEvent::EraseTrackDescriptor(track);
555```
556
557### Flows
558
559Flows can be used to link two (or more) events (slices or instants), to mark
560them as related.
561
562The link is displayed as an arrow in the UI, when one of the events is selected:
563
564![A flow between two slices in the Perfetto UI](
565  /docs/images/flows.png "A flow between two slices in the Perfetto UI")
566
567```C++
568// The same identifier is used in both the related slices.
569uint64_t request_id = GetRequestId();
570
571{
572  TRACE_EVENT("rendering", "HandleRequestPhase1",
573              perfetto::Flow::ProcessScoped(request_id));
574  //...
575}
576
577std::thread t1([&] {
578  TRACE_EVENT("rendering", "HandleRequestPhase2",
579              perfetto::TerminatingFlow::ProcessScoped(request_id));
580  //...
581});
582```
583
584### Counters
585
586Time-varying numeric data can be recorded with the `TRACE_COUNTER` macro:
587
588```C++
589TRACE_COUNTER("category", "MyCounter", 1234.5);
590```
591
592This data is displayed as a counter track in the Perfetto UI:
593
594![A counter track shown in the Perfetto UI](
595  /docs/images/counter-events.png "A counter track shown in the Perfetto UI")
596
597Both integer and floating point counter values are supported. Counters can
598also be annotated with additional information such as units, for example, for
599tracking the rendering framerate in terms of frames per second or "fps":
600
601```C++
602TRACE_COUNTER("category", perfetto::CounterTrack("Framerate", "fps"), 120);
603```
604
605As another example, a memory counter that records bytes but accepts samples
606as kilobytes (to reduce trace binary size) can be defined like this:
607
608```C++
609perfetto::CounterTrack memory_track = perfetto::CounterTrack("Memory")
610    .set_unit("bytes")
611    .set_multiplier(1024);
612TRACE_COUNTER("category", memory_track, 4 /* = 4096 bytes */);
613```
614
615See
616[counter_descriptor.proto](
617/protos/perfetto/trace/track_event/counter_descriptor.proto) for the full set
618of attributes for a counter track.
619
620To record a counter value at a specific point in time (instead of the current
621time), you can pass in a custom timestamp:
622
623```C++
624// First record the current time and counter value.
625uint64_t timestamp = perfetto::TrackEvent::GetTraceTimeNs();
626int64_t value = 1234;
627
628// Later, emit a sample at that point in time.
629TRACE_COUNTER("category", "MyCounter", timestamp, value);
630```
631
632### Interning
633
634Interning can be used to avoid repeating the same constant data (e.g., event
635names) throughout the trace. Perfetto automatically performs interning for
636most strings passed to `TRACE_EVENT`, but it's also possible to also define
637your own types of interned data.
638
639First, define an interning index for your type. It should map to a specific
640field of
641[interned_data.proto](/protos/perfetto/trace/interned_data/interned_data.proto)
642and specify how the interned data is written into that message when seen for
643the first time.
644
645```C++
646struct MyInternedData
647    : public perfetto::TrackEventInternedDataIndex<
648        MyInternedData,
649        perfetto::protos::pbzero::InternedData::kMyInternedDataFieldNumber,
650        const char*> {
651  static void Add(perfetto::protos::pbzero::InternedData* interned_data,
652                   size_t iid,
653                   const char* value) {
654    auto my_data = interned_data->add_my_interned_data();
655    my_data->set_iid(iid);
656    my_data->set_value(value);
657  }
658};
659```
660
661Next, use your interned data in a trace point as shown below. The interned
662string will only be emitted the first time the trace point is hit (unless the
663trace buffer has wrapped around).
664
665```C++
666TRACE_EVENT(
667   "category", "Event", [&](perfetto::EventContext ctx) {
668     auto my_message = ctx.event()->set_my_message();
669     size_t iid = MyInternedData::Get(&ctx, "Repeated data to be interned");
670     my_message->set_iid(iid);
671   });
672```
673
674Note that interned data is strongly typed, i.e., each class of interned data
675uses a separate namespace for identifiers.
676
677### Tracing session observers
678
679The session observer interface allows applications to be notified when track
680event tracing starts and stops:
681
682```C++
683class Observer : public perfetto::TrackEventSessionObserver {
684  public:
685  ~Observer() override = default;
686
687  void OnSetup(const perfetto::DataSourceBase::SetupArgs&) override {
688    // Called when tracing session is configured. Note tracing isn't active yet,
689    // so track events emitted here won't be recorded.
690  }
691
692  void OnStart(const perfetto::DataSourceBase::StartArgs&) override {
693    // Called when a tracing session is started. It is possible to emit track
694    // events from this callback.
695  }
696
697  void OnStop(const perfetto::DataSourceBase::StopArgs&) override {
698    // Called when a tracing session is stopped. It is still possible to emit
699    // track events from this callback.
700  }
701};
702```
703
704Note that all methods of the interface are called on an internal Perfetto
705thread.
706
707For example, here's how to wait for any tracing session to start:
708
709```C++
710class Observer : public perfetto::TrackEventSessionObserver {
711 public:
712  Observer() { perfetto::TrackEvent::AddSessionObserver(this); }
713  ~Observer() { perfetto::TrackEvent::RemoveSessionObserver(this); }
714
715  void OnStart(const perfetto::DataSourceBase::StartArgs&) override {
716    std::unique_lock<std::mutex> lock(mutex);
717    cv.notify_one();
718  }
719
720  void WaitForTracingStart() {
721    printf("Waiting for tracing to start...\n");
722    std::unique_lock<std::mutex> lock(mutex);
723    cv.wait(lock, [] { return perfetto::TrackEvent::IsEnabled(); });
724    printf("Tracing started\n");
725  }
726
727  std::mutex mutex;
728  std::condition_variable cv;
729};
730
731Observer observer;
732observer.WaitForTracingToStart();
733```
734
735[RAII]: https://en.cppreference.com/w/cpp/language/raii
736