Recording In-App Traces with Perfetto

In this guide, you'll learn how to:

  • Use the Perfetto SDK to add custom trace points to a C++ application.
  • Record a trace containing your custom events.
  • Visualize the trace in the Perfetto UI.
  • Programmatically analyze the trace using PerfettoSQL.

The Perfetto SDK is a C++ library that allows you to instrument your application to record trace events. These events can then be visualized and analyzed with the Perfetto UI and Trace Processor.

Adding your first instrumentation

Setup

Checkout the latest SDK release

git clone https://github.com/google/perfetto.git -b v50.1

The SDK consists of two files, sdk/perfetto.h and sdk/perfetto.cc. These are an amalgamation of the Client API designed to easy to integrate to existing build systems. The sources are self-contained and require only a C++17 compliant standard library.

Copy them in your project. The next steps assume they're in the perfetto/sdk folder. Assuming your build looks like this:

You can add the perfetto static library like this:

Initialize perfetto in your program and define your tracing categories:

You can now add instrumentation points to your code. They will emit events when tracing is enabled.

The TRACE_EVENT macro records a scoped event. The event starts when the macro is called and ends at the end of the current scope (e.g., when the function returns). This is the most common type of event and is useful for tracing the duration of a function.

The TRACE_EVENT_BEGIN and TRACE_EVENT_END macros can be used to record events that don't follow function scoping. TRACE_EVENT_BEGIN starts an event, and TRACE_EVENT_END ends the most recent event started on the same thread by default, but can be configured to work across threads and even across processes (see the Track Event documentation for more details). This is useful for tracing operations that span multiple functions.

The TRACE_COUNTER macro records the value of a counter at a specific point in time. This is useful for tracking things like memory usage or the number of items in a queue.

Collecting your first app trace

You can start collecting events with:

And you can stop and save them into a file with:

Visualizing your first app trace

You can now open the example.pftrace file with https://ui.perfetto.dev/

It will show the events captured by the execution of your instrumentation points:

Track event example

Querying your first app trace

As well as visualizing traces on a timeline, Perfetto has support for querying traces using SQL. The easiest way to do this is using the query engine available directly in the UI.

  1. In the Perfetto UI, click on the “Query (SQL)” tab in the left-hand menu.

    Perfetto UI Query SQL

  2. This will open a two-part window. You can write your PerfettoSQL query in the top section and view the results in the bottom section.

    Perfetto UI SQL Window

  3. You can then execute queries Ctrl/Cmd + Enter:

For example, by running:

SELECT
  dur AS duration_ns,
  EXTRACT_ARG(slice.arg_set_id, 'debug.player_number') AS player_number
FROM slice
WHERE slice.name = 'DrawPlayer';

you can see how many times the DrawPlayer instrumentation point has been hit, how long each execution took and its player_number annotation.

SQL query example

The framerate counter is available in the counter table:

SELECT ts AS timestamp_ns, value AS frame_rate
FROM counter
JOIN track ON track.id = counter.track_id
WHERE name = 'Framerate';

Combined In-App and System Tracing

While in-app tracing is useful for understanding your application‘s behavior in isolation, its real power comes from combining it with a system-wide trace. This allows you to see how your app’s events correlate with system events like CPU scheduling, memory usage, and I/O, providing a complete picture of your app's performance in the context of the entire system.

To enable combined tracing, you need to change your application to connect to the system-wide tracing service and then use the standard system tracing tools to record a trace.

  1. Modify your application code:

    • Change the initialization to connect to the system backend (kSystemBackend). This tells the Perfetto SDK to send trace events to the central system tracing service instead of collecting them within the app.
    • Remove all the code related to managing the tracing session (perfetto::Tracing::NewTrace(), tracing_session->Setup(), tracing_session->StartBlocking(), etc.). Your application now only acts as a producer of trace data, and the system tracing service will control when tracing starts and stops.

    Your main function should now look like this:

    #include <perfetto.h>
    
    // Define your categories as before.
    PERFETTO_DEFINE_CATEGORIES(
        perfetto::Category("rendering")
            .SetDescription("Events from the graphics subsystem"),
        perfetto::Category("network")
            .SetDescription("Network upload and download statistics"));
    
    PERFETTO_TRACK_EVENT_STATIC_STORAGE();
    
    int main(int argc, char** argv) {
      // Connect to the system tracing service.
      perfetto::TracingInitArgs args;
      args.backends |= perfetto::kSystemBackend;
      perfetto::Tracing::Initialize(args);
    
      // Register your track event data source.
      perfetto::TrackEvent::Register();
    
      // Your application logic goes here.
      // The TRACE_EVENT macros will now write to the system trace buffer
      // when tracing is enabled externally.
      // ...
    }
    
  2. Record a system trace:

    With your application running, you can now record a combined trace using the methods described in the Recording system traces guide.

    When you configure your trace, you need to enable the track_event data source in addition to any system data sources you want to collect (e.g., linux.ftrace). This will ensure that your application's custom events are included in the trace.

    When you open the resulting trace file in the Perfetto UI, you will see your application's custom tracks alongside the system-level tracks.

Next steps

Now that you've recorded your first in-app trace, you can learn more about instrumenting your code:

  • Tracing SDK: A deep dive into the SDK's features.
  • Track Events: Learn more about the different types of track events and how to use them.