blob: e91fb9e2192781383c5c12895a0ecd56a9a85701 [file] [view] [edit]
# Merging traces with Trace Processor
Trace Processor can import several trace files as one merged trace: events
from every file end up on a single timeline, with their processes, threads
and CPUs kept attributed to the machine they came from. This page shows how
to do it from the command line and in scripted or CI setups. For the
interactive equivalent see
[Merging traces in the Perfetto UI](/docs/visualization/merging-traces.md);
for how the merging actually works see
[How trace merging works](/docs/concepts/merging-traces.md).
## The model: one archive in, one trace out
`trace_processor` takes a single trace file argument. To merge, you pass one
archive (ZIP or TAR) containing the files to merge. The `util merge`
subcommand builds such an archive:
```bash
trace_processor util merge -o merged.tar trace_a.pftrace trace_b.pftrace
trace_processor merged.tar
```
The archive is plain TAR, so `tar cf merged.tar trace_a.pftrace ...` (or any
ZIP tool) works too; `util merge` is just a convenience helper, described
[below](#merge-util).
Everything that accepts a normal trace accepts such an archive: the
interactive shell, `-q` batch queries,
[httpd mode](/docs/analysis/trace-processor.md#subcommands) serving the UI,
and the [C++](/docs/analysis/trace-processor.md#embedding) and
[Python](/docs/analysis/trace-processor-python.md) APIs, which stream the
archive bytes like any other trace.
How the files line up on the timeline is decided by clocks. Three setups
cover most cases, in increasing order of configuration needed.
## {#no-config} Merging that needs no configuration
No extra configuration is needed when Trace Processor can already relate the
files' clocks:
- **Traces from the same device.** Files recorded during the same boot share
clock domains (for example `BOOTTIME`), and files with `ClockSnapshot`
packets relate their domains explicitly.
- **Traces from different devices with wall-clock sync.** `REALTIME` is
assumed to be the same on every machine (in practice: NTP), so two phone
traces recorded at the same time align at their true wall-clock positions
automatically.
- **Traces pre-stamped with a machine id.** An SDK producer initialized with
a machine id tags every packet it writes, so merged files keep their data
on separate machines with no manifest at all:
```c++
perfetto::TracingInitArgs args;
args.backends = perfetto::kInProcessBackend;
args.machine_id = 42; // Non-zero, unique per machine.
perfetto::Tracing::Initialize(args);
```
The C SDK equivalent is `PerfettoProducerBackendInitArgsSetMachineId()`.
A producer can additionally set `SystemInfo.machine_name` to give the
machine a human-readable name in the merged trace.
If neither a shared clock domain nor `REALTIME` can place a file, its events
are dropped rather than guessed (see
[checking the result](#checking) below); that is when you need a manifest.
## {#manifest} Merging with a trace manifest
A [trace manifest](/docs/reference/perfetto-manifest.md)
(`perfetto_manifest`) is a JSON file added to the archive which controls
how Trace Processor interprets the files in it; for merging, it names
machines, remaps embedded machine ids, and manually relates clocks. Trace
Processor always processes it before the trace files, wherever it sits in
the archive.
The manifest is what makes merging automatable. If you are building a tool
that produces several traces per run (a benchmarking framework tracing a
client and a server, a test harness recording one trace per device), your
tool knows how its traces relate; write that down in a manifest and pack
one archive. The archive is then a single self-describing artifact: your
users open it in the UI or in `trace_processor` and get the correctly
merged view every time, with no per-capture configuration.
How your tool builds the archive does not matter: it is ordinary TAR or
ZIP, so any tar/zip library works. The
[`util merge` helper](#merge-util) below is just a convenience for doing
the same thing from the command line, with some validation on top.
### Keeping two devices' data separate
By default, two same-device-looking traces merge onto one machine. Naming
machines keeps each file's processes, threads and CPUs grouped separately:
```json
{
"perfetto_manifest": {
"version": 1,
"files": [
{"path": "device_a.pftrace", "machine": {"name": "device-a"}},
{"path": "device_b.pftrace", "machine": {"name": "device-b"}}
]
}
}
```
```bash
trace_processor util merge -o merged.tar --manifest manifest.json \
device_a.pftrace device_b.pftrace
trace_processor merged.tar
```
Files given the same machine name share one machine; distinct names create
distinct `machine` table rows.
### Placing a clockless trace against a system trace
Formats without absolute clocks (Chrome JSON, Gecko, Instruments) have no
way to line up with a system trace on their own. A `clocks` entry pins the
file to another file's clock, optionally at a fixed offset:
```json
{
"perfetto_manifest": {
"version": 1,
"trace_time": {"clock": "BOOTTIME"},
"files": [
{"path": "system_trace.pftrace"},
{
"path": "app_trace.json",
"clocks": {
"sync_to": {"file": "system_trace.pftrace", "clock": "BOOTTIME"},
"offset_ns": 100000000
}
}
]
}
}
```
`offset_ns` means: at a common instant, the source file's clock reads T when
the reference reads T + `offset_ns`, so a positive value moves the file
later on the timeline. Note that `sync_to.file` must itself appear as an
entry in `files`.
### Renaming machines in a multi-machine trace
A trace recorded with
[traced_relay](/docs/learning-more/multi-machine-tracing.md) already
contains several machines, identified by numeric ids. `machines` gives them
readable names (every embedded id must be listed):
```json
{
"perfetto_manifest": {
"version": 1,
"files": [
{"path": "relay_capture.pftrace", "machines": [
{"id": 0, "name": "host"},
{"id": 1234, "name": "vm"}
]}
]
}
}
```
The full grammar, defaults and error catalog are in
[the trace manifest reference](/docs/reference/perfetto-manifest.md).
TIP: the Perfetto UI's "Open multiple trace files" dialog generates this
format interactively: configure the merge there, then use "Copy manifest" or
"Download .tar" to bootstrap a scripted setup.
### {#merge-util} Packing with util merge
`util merge` is optional: since the archive is ordinary TAR (or ZIP), you
can just as well tar/zip the trace files and manifest together yourself.
The helper takes care of the archive layout (member naming, and including
the manifest as `perfetto_manifest.json` whatever the file passed via
`--manifest` is called) and runs sanity checks on the result, warning if
the archive would not merge cleanly. `--strict` turns the warnings into a
failing exit code, useful in CI; `--no-validate` skips the checks.
## {#checking} Checking the result
The merged trace exposes what happened during the merge:
```sql
-- The machines in the merged trace and how much data each has.
SELECT
m.name,
m.raw_id,
(SELECT COUNT(*) FROM thread t WHERE t.machine_id = m.id) AS threads
FROM machine m;
-- The input files and the order they were processed in.
SELECT name, trace_type, size FROM trace_file;
-- Anything dropped or misaligned during the merge. An empty result means
-- every event was placed on the timeline.
SELECT name, value, machine_id, trace_id
FROM stats
WHERE severity = 'error' AND value > 0;
```
The stats to watch for merges: `clock_sync_unrelatable_clock_domains` and
`clock_sync_failure_no_path` count events whose clock could not be related
to the timeline (record clock snapshots or add a manifest `clocks` entry);
`trace_sorter_negative_timestamp_dropped` counts events an `offset_ns`
moved before the start of the timeline.
Per-file metadata is available via the `metadata` table's `trace_id` column
or, at a higher level, the `_metadata_by_trace` view in the
`traceinfo.trace` stdlib module.
## Interop notes
- **Android bugreports**: `bugreport.zip` files already open as archives;
Trace Processor extracts and merges the traces inside.
- **traceconv bundle**: the TAR produced by
[`traceconv bundle`](/docs/quickstart/traceconv.md) (trace plus symbols)
is the same archive mechanism.
- **Python `BatchTraceProcessor`** does not merge: it loads N traces into N
independent instances for parallel querying. To merge, pass one archive
to a single `TraceProcessor` instance.
- Archives containing archives cannot be merged recursively; merge the leaf
files directly.
## Next steps
- [Trace manifest format](/docs/reference/perfetto-manifest.md): the
normative reference for the manifest.
- [How trace merging works](/docs/concepts/merging-traces.md): clock graph,
placement rules and the machine model.
- [Multi-machine recording](/docs/learning-more/multi-machine-tracing.md):
recording a single trace from several machines live, instead of merging
after the fact.