1# Tracing SDK 2 3The Perfetto Tracing SDK is a C++17 library that allows userspace applications 4to emit trace events and add more app-specific context to a Perfetto trace. 5 6When using the Tracing SDK there are two main aspects to consider: 7 81. Whether you are interested only in tracing events coming from your own app 9 or want to collect full-stack traces that overlay app trace events with 10 system trace events like scheduler traces, syscalls or any other Perfetto 11 data source. 12 132. For app-specific tracing, whether you need to trace simple types of timeline 14 events (e.g., slices, counters) or need to define complex data sources with a 15 custom strongly-typed schema (e.g., for dumping the state of a subsystem of 16 your app into the trace). 17 18For Android-only instrumentation, the advice is to keep using the existing 19[android.os.Trace (SDK)][atrace-sdk] / [ATrace_* (NDK)][atrace-ndk] if they 20are sufficient for your use cases. Atrace-based instrumentation is fully 21supported in Perfetto. 22See the [Data Sources -> Android System -> Atrace Instrumentation][atrace-ds] 23for details. 24 25## Getting started 26 27TIP: The code from these examples is also available [in the 28repository](/examples/sdk/README.md). 29 30To start using the Client API, first check out the latest SDK release: 31 32```bash 33git clone https://android.googlesource.com/platform/external/perfetto -b v34.0 34``` 35 36The SDK consists of two files, `sdk/perfetto.h` and `sdk/perfetto.cc`. These are 37an amalgamation of the Client API designed to easy to integrate to existing 38build systems. The sources are self-contained and require only a C++17 compliant 39standard library. 40 41For example, to add the SDK to a CMake project, edit your CMakeLists.txt: 42 43```cmake 44cmake_minimum_required(VERSION 3.13) 45project(PerfettoExample) 46find_package(Threads) 47 48# Define a static library for Perfetto. 49include_directories(perfetto/sdk) 50add_library(perfetto STATIC perfetto/sdk/perfetto.cc) 51 52# Link the library to your main executable. 53add_executable(example example.cc) 54target_link_libraries(example perfetto ${CMAKE_THREAD_LIBS_INIT}) 55 56if (WIN32) 57 # The perfetto library contains many symbols, so it needs the big object 58 # format. 59 target_compile_options(perfetto PRIVATE "/bigobj") 60 # Disable legacy features in windows.h. 61 add_definitions(-DWIN32_LEAN_AND_MEAN -DNOMINMAX) 62 # On Windows we should link to WinSock2. 63 target_link_libraries(example ws2_32) 64endif (WIN32) 65 66# Enable standards-compliant mode when using the Visual Studio compiler. 67if (MSVC) 68 target_compile_options(example PRIVATE "/permissive-") 69endif (MSVC) 70``` 71 72Next, initialize Perfetto in your program: 73 74```C++ 75#include <perfetto.h> 76 77int main(int argc, char** argv) { 78 perfetto::TracingInitArgs args; 79 80 // The backends determine where trace events are recorded. You may select one 81 // or more of: 82 83 // 1) The in-process backend only records within the app itself. 84 args.backends |= perfetto::kInProcessBackend; 85 86 // 2) The system backend writes events into a system Perfetto daemon, 87 // allowing merging app and system events (e.g., ftrace) on the same 88 // timeline. Requires the Perfetto `traced` daemon to be running (e.g., 89 // on Android Pie and newer). 90 args.backends |= perfetto::kSystemBackend; 91 92 perfetto::Tracing::Initialize(args); 93} 94``` 95 96You are now ready to instrument your app with trace events. 97 98## Custom data sources vs Track events 99 100The SDK offers two abstraction layers to inject tracing data, built on top of 101each other, which trade off code complexity vs expressive power: 102[track events](#track-events) and [custom data sources](#custom-data-sources). 103 104### Track events 105 106Track events are the suggested option when dealing with app-specific tracing as 107they take care of a number of subtleties (e.g., thread safety, flushing, string 108interning). 109Track events are time bounded events (e.g., slices, counter) based on simple 110`TRACE_EVENT` annotation tags in the codebase, like this: 111 112```c++ 113#include <perfetto.h> 114 115PERFETTO_DEFINE_CATEGORIES( 116 perfetto::Category("rendering") 117 .SetDescription("Events from the graphics subsystem"), 118 perfetto::Category("network") 119 .SetDescription("Network upload and download statistics")); 120 121PERFETTO_TRACK_EVENT_STATIC_STORAGE(); 122... 123 124int main(int argc, char** argv) { 125 ... 126 perfetto::Tracing::Initialize(args); 127 perfetto::TrackEvent::Register(); 128} 129 130... 131 132void LayerTreeHost::DoUpdateLayers() { 133 TRACE_EVENT("rendering", "LayerTreeHost::DoUpdateLayers"); 134 ... 135 for (PictureLayer& pl : layers) { 136 TRACE_EVENT("rendering", "PictureLayer::Update"); 137 pl.Update(); 138 } 139} 140``` 141 142Which are rendered in the UI as follows: 143 144 145 146Track events are the best default option and serve most tracing use cases with 147very little complexity. 148 149To include your new track events in the trace, ensure that the `track_event` 150data source is included in the trace config. If you do not specify any 151categories then all non-debug categories will be included by default. However, 152you can also add just the categories you are interested in like so: 153 154```protobuf 155data_sources { 156 config { 157 name: "track_event" 158 track_event_config { 159 enabled_categories: "rendering" 160 } 161 } 162} 163``` 164 165See the [Track events page](track-events.md) for full instructions. 166 167### Custom data sources 168 169For most uses, track events are the most straightforward way of instrumenting 170apps for tracing. However, in some rare circumstances they are not 171flexible enough, e.g., when the data doesn't fit the notion of a track or is 172high volume enough that it needs a strongly typed schema to minimize the size of 173each event. In this case, you can implement a *custom data source* for 174Perfetto. 175 176Unlike track events, when working with custom data sources, you will also need 177corresponding changes in [trace processor](/docs/analysis/trace-processor.md) 178to enable importing your data format. 179 180A custom data source is a subclass of `perfetto::DataSource`. Perfetto will 181automatically create one instance of the class for each tracing session it is 182active in (usually just one). 183 184```C++ 185class CustomDataSource : public perfetto::DataSource<CustomDataSource> { 186 public: 187 void OnSetup(const SetupArgs&) override { 188 // Use this callback to apply any custom configuration to your data source 189 // based on the TraceConfig in SetupArgs. 190 } 191 192 void OnStart(const StartArgs&) override { 193 // This notification can be used to initialize the GPU driver, enable 194 // counters, etc. StartArgs will contains the DataSourceDescriptor, 195 // which can be extended. 196 } 197 198 void OnStop(const StopArgs&) override { 199 // Undo any initialization done in OnStart. 200 } 201 202 // Data sources can also have per-instance state. 203 int my_custom_state = 0; 204}; 205 206PERFETTO_DECLARE_DATA_SOURCE_STATIC_MEMBERS(CustomDataSource); 207``` 208 209The data source's static data should be defined in one source file like this: 210 211```C++ 212PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(CustomDataSource); 213``` 214 215Custom data sources need to be registered with Perfetto: 216 217```C++ 218int main(int argc, char** argv) { 219 ... 220 perfetto::Tracing::Initialize(args); 221 // Add the following: 222 perfetto::DataSourceDescriptor dsd; 223 dsd.set_name("com.example.custom_data_source"); 224 CustomDataSource::Register(dsd); 225} 226``` 227 228As with all data sources, the custom data source needs to be specified in the 229trace config to enable tracing: 230 231```C++ 232perfetto::TraceConfig cfg; 233auto* ds_cfg = cfg.add_data_sources()->mutable_config(); 234ds_cfg->set_name("com.example.custom_data_source"); 235``` 236 237Finally, call the `Trace()` method to record an event with your custom data 238source. The lambda function passed to that method will only be called if tracing 239is enabled. It is always called synchronously and possibly multiple times if 240multiple concurrent tracing sessions are active. 241 242```C++ 243CustomDataSource::Trace([](CustomDataSource::TraceContext ctx) { 244 auto packet = ctx.NewTracePacket(); 245 packet->set_timestamp(perfetto::TrackEvent::GetTraceTimeNs()); 246 packet->set_for_testing()->set_str("Hello world!"); 247}); 248``` 249 250If necessary the `Trace()` method can access the custom data source state 251(`my_custom_state` in the example above). Doing so, will take a mutex to 252ensure data source isn't destroyed (e.g., because of stopping tracing) while 253the `Trace()` method is called on another thread. For example: 254 255```C++ 256CustomDataSource::Trace([](CustomDataSource::TraceContext ctx) { 257 auto safe_handle = trace_args.GetDataSourceLocked(); // Holds a RAII lock. 258 DoSomethingWith(safe_handle->my_custom_state); 259}); 260``` 261 262## In-process vs System mode 263 264The two modes are not mutually exclusive. An app can be configured to work 265in both modes and respond both to in-process tracing requests and system 266tracing requests. Both modes generate the same trace file format. 267 268### In-process mode 269 270In this mode both the perfetto service and the app-defined data sources are 271hosted fully in-process, in the same process of the profiled app. No connection 272to the system `traced` daemon will be attempted. 273 274In-process mode can be enabled by setting 275`TracingInitArgs.backends = perfetto::kInProcessBackend` when initializing the 276SDK, see examples below. 277 278This mode is used to generate traces that contain only events emitted by 279the app, but not other types of events (e.g. scheduler traces). 280 281The main advantage is that by running fully in-process, it doesn't require any 282special OS privileges and the profiled process can control the lifecycle of 283tracing sessions. 284 285This mode is supported on Android, Linux, MacOS and Windows. 286 287### System mode 288 289In this mode the app-defined data sources will connect to the external `traced` 290service using the [IPC over UNIX socket][ipc]. 291 292System mode can be enabled by setting 293`TracingInitArgs.backends = perfetto::kSystemBackend` when initializing the SDK, 294see examples below. 295 296The main advantage of this mode is that it is possible to create fused traces where 297app events are overlaid on the same timeline of OS events. This enables 298full-stack performance investigations, looking all the way through syscalls and 299kernel scheduling events. 300 301The main limitation of this mode is that it requires the external `traced` daemon 302to be up and running and reachable through the UNIX socket connection. 303 304This is suggested for local debugging or lab testing scenarios where the user 305(or the test harness) can control the OS deployment (e.g., sideload binaries on 306Android). 307 308When using system mode, the tracing session must be controlled from the outside, 309using the `perfetto` command-line client 310(See [reference](/docs/reference/perfetto-cli)). This is because when collecting 311system traces, tracing data producers are not allowed to read back the trace 312data as it might disclose information about other processes and allow 313side-channel attacks. 314 315* On Android 9 (Pie) and beyond, traced is shipped as part of the platform. 316* On older versions of Android, traced can be built from sources using the 317 the [standalone NDK-based workflow](/docs/contributing/build-instructions.md) 318 and sideloaded via adb shell. 319* On Linux and MacOS and Windows `traced` must be built and run separately. See 320 the [Linux quickstart](/docs/quickstart/linux-tracing.md) for instructions. 321* On Windows the tracing protocol works over TCP/IP ( 322 [127.0.0.1:32278](https://cs.android.com/android/platform/superproject/+/master:external/perfetto/src/tracing/ipc/default_socket.cc;l=75;drc=4f88a2fdfd3801c109d5e927b8206f9756288b12) 323 ) + named shmem. 324 325## {#recording} Recording traces through the API 326 327_Tracing through the API is currently only supported with the in-process mode. 328When using system mode, use the `perfetto` cmdline client (see quickstart 329guides)._ 330 331First initialize a [TraceConfig](/docs/reference/trace-config-proto.autogen) 332message which specifies what type of data to record. 333 334If your app includes [track events](track-events.md) (i.e, `TRACE_EVENT`), you 335typically want to choose the categories which are enabled for tracing. 336 337By default, all non-debug categories are enabled, but you can enable a specific 338one like this: 339 340```C++ 341perfetto::protos::gen::TrackEventConfig track_event_cfg; 342track_event_cfg.add_disabled_categories("*"); 343track_event_cfg.add_enabled_categories("rendering"); 344``` 345 346Next, build the main trace config together with the track event part: 347 348```C++ 349perfetto::TraceConfig cfg; 350cfg.add_buffers()->set_size_kb(1024); // Record up to 1 MiB. 351auto* ds_cfg = cfg.add_data_sources()->mutable_config(); 352ds_cfg->set_name("track_event"); 353ds_cfg->set_track_event_config_raw(track_event_cfg.SerializeAsString()); 354``` 355 356If your app includes a custom data source, you can also enable it here: 357 358```C++ 359ds_cfg = cfg.add_data_sources()->mutable_config(); 360ds_cfg->set_name("my_data_source"); 361``` 362 363After building the trace config, you can begin tracing: 364 365```C++ 366std::unique_ptr<perfetto::TracingSession> tracing_session( 367 perfetto::Tracing::NewTrace()); 368tracing_session->Setup(cfg); 369tracing_session->StartBlocking(); 370``` 371 372TIP: API methods with `Blocking` in their name will suspend the calling thread 373 until the respective operation is complete. There are also asynchronous 374 variants that don't have this limitation. 375 376Now that tracing is active, instruct your app to perform the operation you 377want to record. After that, stop tracing and collect the 378protobuf-formatted trace data: 379 380```C++ 381tracing_session->StopBlocking(); 382std::vector<char> trace_data(tracing_session->ReadTraceBlocking()); 383 384// Write the trace into a file. 385std::ofstream output; 386output.open("example.perfetto-trace", std::ios::out | std::ios::binary); 387output.write(&trace_data[0], trace_data.size()); 388output.close(); 389``` 390 391To save memory with longer traces, you can also tell Perfetto to write 392directly into a file by passing a file descriptor into Setup(), remembering 393to close the file after tracing is done: 394 395```C++ 396int fd = open("example.perfetto-trace", O_RDWR | O_CREAT | O_TRUNC, 0600); 397tracing_session->Setup(cfg, fd); 398tracing_session->StartBlocking(); 399// ... 400tracing_session->StopBlocking(); 401close(fd); 402``` 403 404The resulting trace file can be directly opened in the [Perfetto 405UI](https://ui.perfetto.dev) or the [Trace Processor](/docs/analysis/trace-processor.md). 406 407[ipc]: /docs/design-docs/api-and-abi.md#socket-protocol 408[atrace-ds]: /docs/data-sources/atrace.md 409[atrace-ndk]: https://developer.android.com/ndk/reference/group/tracing 410[atrace-sdk]: https://developer.android.com/reference/android/os/Trace 411