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 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 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 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 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