The Next Generation of Tracing
Perfetto is the modern, unified tracing and profiling platform for Android, Chrome, and Linux. It was introduced to solve the limitations of Systrace, specifically regarding long-running traces, massive data volumes, and cross-platform compatibility.
While Systrace relied on a circular buffer that easily overflowed on busy systems, Perfetto uses a highly efficient protocol buffer based architecture designed for sustained, high-throughput tracing.
Perfetto Architecture
The core of Perfetto revolves around a set of daemon processes that manage data collection.
1. traced (Tracing Service)
This is the central daemon. It acts as the orchestrator, managing trace sessions, routing data from producers to the final trace file, and handling trace configuration.
2. Producers (traced_probes and Apps)
Producers are processes that feed data into traced.
traced_probes: A specialized daemon that gathers system-level metrics. It reads from Linuxftrace(for CPU scheduling, syscalls, andatraceevents),procfs(for memory stats), and other kernel interfaces.- Applications/Services: Android apps and system services can link against the Perfetto SDK (or use standard
atracewhich is intercepted by Perfetto) to emit custom events directly totraced.
Perfetto Configuration and Data Sources
Unlike Systrace's simple command-line flags, Perfetto uses a powerful protobuf configuration file to specify exactly what data to collect. This allows for incredibly fine-grained control over sampling rates and buffer sizes.
Common Data Sources include:
linux.ftrace: Captures kernel events. You configure this to enablesched_switch(CPU scheduling),print(which capturesatracemarkers from Android), and specific hardware drivers.linux.process_stats: Polls/proc/<pid>/statusand/proc/<pid>/oom_score_adjto track memory usage and process lifecycle events over time.linux.sys_stats: Captures system-wide CPU frequency and memory info.android.heapprofd: Enables native heap profiling for memory leak detection.android.java_hprof: Triggers Java heap dumps.
A minimal configuration to capture CPU scheduling and app traces looks like this:
buffers: {
size_kb: 63488
fill_policy: RING_BUFFER
}
data_sources: {
config {
name: "linux.ftrace"
ftrace_config {
ftrace_events: "sched/sched_switch"
ftrace_events: "power/cpu_frequency"
atrace_categories: "am"
atrace_categories: "wm"
atrace_categories: "view"
atrace_categories: "gfx"
atrace_apps: "com.example.myapp"
}
}
}
duration_ms: 10000
You push this config to the device and run:
cat trace_config.pb | adb shell perfetto -c - -o /data/misc/perfetto-traces/trace.perfetto-trace
Trace Analysis in Perfetto UI
The primary way to view Perfetto traces is through the web based interface: https://ui.perfetto.dev.
When you open a trace, the UI provides a visual timeline similar to Systrace but with vastly improved performance and features. Key UI components include:
- Pinned Tracks: Keep important metrics (like CPU frequency or a specific thread) at the top of the screen while scrolling.
- Thread State Aggregation: Select a region of time across a thread to see a summary of how much time it spent Running vs. Sleeping vs. Blocked.
- Flamegraphs: If the trace includes profiling data (like callstacks from CPU profiling), the UI can render flamegraphs to identify hot paths in the code.
SQL Queries on Perfetto Traces
The most powerful feature of Perfetto is Trace Processor. Perfetto ingests the protobuf trace file and exposes it as an in-memory SQLite database. This allows you to run complex SQL queries to extract aggregate performance metrics, something that was nearly impossible with Systrace.
You can run these queries directly in the ui.perfetto.dev interface (using the query box at the top) or using the trace_processor command-line tool.
Example: Find the longest running drawFrame slices
SELECT
slice.name,
slice.ts,
slice.dur / 1e6 AS duration_ms,
thread.name AS thread_name
FROM slice
JOIN thread_track ON slice.track_id = thread_track.id
JOIN thread USING(utid)
WHERE slice.name = 'drawFrame'
ORDER BY slice.dur DESC
LIMIT 10;
Example: Calculate total CPU time per process
SELECT
process.name,
SUM(dur) / 1e9 AS cpu_time_seconds
FROM sched
JOIN thread USING(utid)
JOIN process USING(upid)
GROUP BY process.name
ORDER BY cpu_time_seconds DESC;
Heap Profiling with Perfetto
Perfetto is not just for timelines; it is also a powerful profiling tool.
Using the android.heapprofd data source, Perfetto can intercept malloc and free calls in native code (C/C++). It records the call stack for every allocation.
When you load a heapprofd trace into the Perfetto UI, it displays a flamegraph of memory allocations. This makes it trivial to identify exactly which function is leaking native memory, a task that used to require complex setups with malloc_debug or ASan.
Recording Long Traces
For elusive bugs that take hours to reproduce, Perfetto supports long traces. Instead of keeping all data in a ring buffer in memory, Perfetto can stream trace data directly to disk.
By setting the buffer policy to DISCARD (instead of RING_BUFFER) and configuring the write_into_file option, Perfetto will periodically flush its internal buffers to the filesystem. You can configure it to write traces up to several gigabytes in size, capturing hours of system activity for post-mortem analysis.