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