Quickstart: SQL-based analysis and trace-based metrics
This quickstart explains how to use trace_processor
as well as its Python API to
programmatically query the trace contents through SQL and compute trace-based metrics.
Trace Processor
TraceProcessor is a multi-format trace importing and query engine based on
SQLite. It comes both as a C++ library and as a standalone executable:
trace_processor_shell
(or just trace_processor
).
Setup
# Download prebuilts (Linux and Mac only)
curl -LO https://get.perfetto.dev/trace_processor
chmod +x ./trace_processor
# Start the interactive shell
./trace_processor trace.perfetto-trace
# Start a local trace processor instance to replace wasm module in the UI
./trace_processor trace.perfetto-trace --httpd
NOTE: In HTTP mode the trace will be loaded into the trace_processor
and
the UI will connect and issue queries over TCP. This can allow
arbitrary sized traces to be loaded since there are no memory
constraints, unlike the WASM module. In addition, this can improve
performance in the UI as it issues SQL queries.
See Trace Processor docs for the full TraceProcessor guide.
Sample queries
For more exhaustive examples see the SQL section of the various Data sources docs.
Slices
Slices are stackable events which have name and span some duration of time.
> SELECT ts, dur, name FROM slice
ts dur name
-------------------- -------------------- ---------------------------
261187017446933 358594 eglSwapBuffersWithDamageKHR
261187017518340 357 onMessageReceived
261187020825163 9948 queueBuffer
261187021345235 642 bufferLoad
261187121345235 153 query
...
Counters
Counters are events with a value which changes over time.
> SELECT ts, value FROM counter
ts value
-------------------- --------------------
261187012149954 1454.000000
261187012399172 4232.000000
261187012447402 14304.000000
261187012535839 15490.000000
261187012590890 17490.000000
261187012590890 16590.000000
...
Scheduler slices
Scheduler slices indicate which thread was scheduled on which CPU at which time.
> SELECT ts, dur, cpu, utid FROM sched
ts dur cpu utid
-------------------- -------------------- -------------------- --------------------
261187012170489 267188 0 390
261187012170995 247153 1 767
261187012418183 12812 2 2790
261187012421099 220000 6 683
261187012430995 72396 7 2791
...
Trace-based metrics
Trace Processor offers also a higher-level query interface that allows to run pre-baked queries, herein called "metrics". Metrics are generally curated by domain experts, often the same people who add the instrumentation points in the first place, and output structured JSON/Protobuf/text. Metrics allow to get a summarized view of the trace without having to type any SQL or having to load the trace in the UI.
The metrics` schema files live in the /protos/perfetto/metrics directory. The corresponding SQL queries live in /src/trace_processor/metrics.
Run a single metric
Let's run the android_cpu
metric. This metrics computes the total CPU time and the total cycles
(CPU frequency * time spent running at that frequency) for each process in the
trace, breaking it down by CPU (core) number.
./trace_processor --run-metrics android_cpu trace.perfetto-trace
android_cpu {
process_info {
name: "/system/bin/init"
threads {
name: "init"
core {
id: 1
metrics {
mcycles: 1
runtime_ns: 570365
min_freq_khz: 1900800
max_freq_khz: 1900800
avg_freq_khz: 1902017
}
}
core {
id: 3
metrics {
mcycles: 0
runtime_ns: 366406
min_freq_khz: 1900800
max_freq_khz: 1900800
avg_freq_khz: 1902908
}
}
...
}
...
}
process_info {
name: "/system/bin/logd"
threads {
name: "logd.writer"
core {
id: 0
metrics {
mcycles: 8
runtime_ns: 33842357
min_freq_khz: 595200
max_freq_khz: 1900800
avg_freq_khz: 1891825
}
}
core {
id: 1
metrics {
mcycles: 9
runtime_ns: 36019300
min_freq_khz: 1171200
max_freq_khz: 1900800
avg_freq_khz: 1887969
}
}
...
}
...
}
...
}
Running multiple metrics
Multiple metrics can be flagged using comma separators to the --run-metrics
flag. This will output a text proto with the combined result of running both
metrics.
$ ./trace_processor --run-metrics android_mem,android_cpu trace.perfetto-trace
android_mem {
process_metrics {
process_name: ".dataservices"
total_counters {
anon_rss {
min: 19451904
max: 19890176
avg: 19837548.157829277
}
file_rss {
min: 25804800
max: 25829376
avg: 25827909.957489081
}
swap {
min: 9289728
max: 9728000
avg: 9342355.8421707246
}
anon_and_swap {
min: 29179904
max: 29179904
avg: 29179904
}
}
...
}
...
}
android_cpu {
process_info {
name: "/system/bin/init"
threads {
name: "init"
core {
id: 1
metrics {
mcycles: 1
runtime_ns: 570365
min_freq_khz: 1900800
max_freq_khz: 1900800
avg_freq_khz: 1902017
}
}
...
}
...
}
...
}
JSON and binary output
The trace processor also supports binary protobuf and JSON as alternative output formats. This is useful when the intended reader is an offline tool.
Both single and multiple metrics are supported as with proto text output.
./trace_processor --run-metrics android_mem --metrics-output=binary trace.perfetto-trace
<binary protobuf output>
./trace_processor --run-metrics android_mem,android_cpu --metrics-output=json trace.perfetto-trace
{
"android_mem": {
"process_metrics": [
{
"process_name": ".dataservices",
"total_counters": {
"anon_rss": {
"min": 19451904.000000,
"max": 19890176.000000,
"avg": 19837548.157829
},
"file_rss": {
"min": 25804800.000000,
"max": 25829376.000000,
"avg": 25827909.957489
},
"swap": {
"min": 9289728.000000,
"max": 9728000.000000,
"avg": 9342355.842171
},
"anon_and_swap": {
"min": 29179904.000000,
"max": 29179904.000000,
"avg": 29179904.000000
}
},
...
},
...
]
}
"android_cpu": {
"process_info": [
{
"name": "\/system\/bin\/init",
"threads": [
{
"name": "init",
"core": [
{
"id": 1,
"metrics": {
"mcycles": 1,
"runtime_ns": 570365,
"min_freq_khz": 1900800,
"max_freq_khz": 1900800,
"avg_freq_khz": 1902017
}
},
...
]
...
}
...
]
...
},
...
]
...
}
}
Python API
The API can be run without requiring the trace_processor
binary to be
downloaded or installed.
Setup
$ pip install perfetto
NOTE: The API is only compatible with Python3.
Example functions
See the Python API section of Trace Processor (SQL) to get more details on all available functions.
Query
from perfetto.trace_processor import TraceProcessor
tp = TraceProcessor(trace='trace.perfetto-trace')
qr_it = tp.query('SELECT name FROM slice')
for row in qr_it:
print(row.name)
Output
eglSwapBuffersWithDamageKHR
onMessageReceived
queueBuffer
bufferLoad
query
...
Query as Pandas DataFrame
from perfetto.trace_processor import TraceProcessor
tp = TraceProcessor(trace='trace.perfetto-trace')
qr_it = tp.query('SELECT ts, name FROM slice')
qr_df = qr_it.as_pandas_dataframe()
print(qr_df.to_string())
Output
ts name
---------------------------
261187017446933 eglSwapBuffersWithDamageKHR
261187017518340 onMessageReceived
261187020825163 queueBuffer
261187021345235 bufferLoad
261187121345235 query
...
Metric
from perfetto.trace_processor import TraceProcessor
tp = TraceProcessor(trace='trace.perfetto-trace')
cpu_metrics = tp.metric(['android_cpu'])
print(cpu_metrics)
Output
metrics {
android_cpu {
process_info {
name: "/system/bin/init"
threads {
name: "init"
core {
id: 1
metrics {
mcycles: 1
runtime_ns: 570365
min_freq_khz: 1900800
max_freq_khz: 1900800
avg_freq_khz: 1902017
}
}
core {
id: 3
metrics {
mcycles: 0
runtime_ns: 366406
min_freq_khz: 1900800
max_freq_khz: 1900800
avg_freq_khz: 1902908
}
}
...
}
...
}
...
}
}
Next steps
There are several options for exploring more of the trace analysis features Perfetto provides:
- The trace conversion quickstart gives an overview on how to convert Perfetto traces to legacy formats to integrate with existing tooling.
- The Trace Processor documentation gives more information about how to work with trace processor including details on how to write queries and how tables in trace processor are organized.
- The metrics documentation gives a more in-depth look into metrics including a short walkthrough on how to build an experimental metric from scratch.
- The SQL table reference gives a comprehensive guide to the all the available tables in trace processor.
- The common tasks page gives a list of steps on how new metrics can be added to the trace processor.