Trace manifest format

A trace manifest (perfetto_manifest) is a JSON file placed inside a trace archive (ZIP or TAR) which controls how Trace Processor and the Perfetto UI interpret the other files in the archive. It is a general mechanism; the fields defined so far configure how multiple trace files merge onto a single timeline (which machine each file belongs to, how their clocks relate, and which clock the merged trace uses as its timeline) and attach attributes annotating the archive.

This page is the normative reference for the format. For a task-oriented guide to merging see Merging traces with Trace Processor; for the underlying model see How trace merging works.

The format is stable: version 1 is the current (and only) version and will remain supported. New capabilities are added as new fields within version 1; fields a given Trace Processor version does not know are ignored.

Why a manifest?

The Perfetto UI's merge dialog configures a merge interactively, which is the right tool for a one-off investigation. The manifest exists for when the merge is not a one-off: tools and systems that produce several related traces per run, such as a benchmarking framework tracing a client and a server, a test harness recording one trace per device, or a pipeline capturing an app trace next to a system trace.

Such a tool should not make every user reconstruct the merge configuration in a dialog for every capture. It knows how its traces relate; the manifest is how it writes that knowledge down. The tool emits the manifest alongside the traces and packs everything into one archive, and that archive becomes a single self-describing artifact: anyone can open it in the UI or in trace_processor and get the correctly merged view with zero configuration, today or years later.

The interactive dialog and the manifest are two faces of the same mechanism: the dialog generates a manifest under the hood, and its “Copy manifest” button is a convenient way to get a starting template. Since file names, offsets and machine names usually vary per capture, tools generally generate the manifest programmatically for each run and pack it into the archive together with the trace files.

Example

{
  "perfetto_manifest": {
    "version": 1,
    "trace_time": {"clock": "BOOTTIME"},
    "files": [
      {"path": "phone.pftrace", "machine": {"name": "phone"}},
      {"path": "watch.pftrace", "machine": {"name": "watch"}},
      {
        "path": "app_log.json",
        "clocks": {
          "sync_to": {"file": "phone.pftrace", "clock": "BOOTTIME"},
          "offset_ns": 250000000
        }
      }
    ]
  }
}

Detection and placement

Trace Processor detects a manifest by content, not by file name: any file whose contents (after leading whitespace) start with {"perfetto_manifest" is treated as a manifest. By convention the file is named perfetto_manifest.json, and that is the name the Perfetto UI uses when it generates one, but any name works.

Placement rules:

  • Inside a ZIP or TAR archive: position does not matter. Trace Processor always processes the manifest before any trace file, regardless of where it appears in the archive.
  • In a concatenated stream (for example gzip members concatenated together): the manifest must come first. A manifest encountered after another trace file is rejected with an error.
  • At most one manifest per merged input. A second one is an error.
  • A standalone manifest (not inside an archive) parses successfully but has nothing to configure.

The manifest is applied in full before any trace file is parsed, so entries may reference files in any order, including files that appear later in the archive.

Top-level fields

The document is a JSON object with a single top-level perfetto_manifest key, containing:

FieldTypeRequiredDescription
versionintegeryesMust be 1. Any other value is rejected.
trace_timeobjectnoSelects the clock of the merged timeline. See trace_time.
filesarraynoPer-file configuration entries. See files.
attributesobjectnoKey/value pairs annotating the archive. See attributes.

Files present in the archive but not listed in files are still imported; they just get no overrides and follow the default merging rules described in How trace merging works.

trace_time

Selects the clock that becomes the merged trace's timeline (its “trace time”). Without it, the first file to claim a trace-time clock wins.

FieldTypeRequiredDescription
clockstringyesOne of the clock names.
filestringnoPins the clock to the machine of this file. Must match the path of an entry in files.
machinestringnoWhen file is a multi-machine trace, names which of its machines owns the clock. Requires file.

Every clock is scoped to a machine: BOOTTIME on the phone and BOOTTIME on the watch are different clocks. file (and machine) select whose clock becomes the timeline; without them the host machine's clock is used.

The selected clock id is recorded in the metadata table under the trace_time_clock_id key.

files

Each entry in the files array is an object:

FieldTypeRequiredDescription
pathstringyesThe exact name of a file in the archive (for TAR/ZIP, the member path).
machineobjectnoAttributes the whole file to a named machine. Mutually exclusive with machines.
machinesarraynoRemaps a multi-machine trace's embedded machine ids to named machines. Mutually exclusive with machine.
clocksobjectnoManually relates this file's clock to a clock in another file. See clocks.

machine

{"path": "watch.pftrace", "machine": {"name": "watch"}}
FieldTypeRequiredDescription
namestring (non-empty)yesThe machine's name.

Attributes every event in the file to a machine with the given name. Files (or machines entries) using the same name share a single machine: their processes, threads and CPUs are grouped together in the merged trace. Using distinct names keeps each device's data separate.

machine is an object rather than a bare string so future per-machine attributes can be added without a format change.

It is an error to use machine on a file that itself contains data from several machines (a multi-machine proto trace recorded via traced_relay); use machines for those.

machines

{"path": "relay.pftrace", "machines": [
  {"id": 0, "name": "host"},
  {"id": 1234, "name": "vm"}
]}
FieldTypeRequiredDescription
idinteger in [0, 4294967295]yesA machine id embedded in the trace's packets.
namestring (non-empty)yesThe name to give that machine.

Renames the machines already embedded in a multi-machine trace. Every embedded id which appears in the trace must be declared; a packet from an undeclared id is an error. An entry with id: 0 also becomes the file's base machine. Names share the same namespace as machine names, so the same name in two files merges them into one machine.

clocks

Manually places this file on the shared timeline by relating one of its clocks to a clock in another file. Use this when the automatic rules (shared clock domains, REALTIME rendezvous) cannot place the file, or to apply a known fixed offset.

{
  "path": "app_log.json",
  "clocks": {
    "sync_to": {"file": "phone.pftrace", "clock": "BOOTTIME"},
    "offset_ns": 250000000
  }
}
FieldTypeRequiredDescription
clockstringnoWhich of this file's own clocks to relate, as a clock name. Omit for clockless files.
machinestringnoWhen this file is multi-machine, names which of its machines owns the source clock. Required in that case.
sync_toobjectyesThe reference clock. See below.
offset_nsintegerno (default 0)Fixed offset between the two clocks: at a common instant, the source clock reads T when the reference clock reads T + offset_ns. A positive value therefore moves this file later on the reference's timeline.

sync_to fields:

FieldTypeRequiredDescription
filestringyesThe reference file. Must match the path of an entry in files.
machinestringnoWhen the reference file is multi-machine, names which of its declared machines owns the reference clock. Required in that case. A machine name alone (without file) is rejected as ambiguous.
clockstringnoThe reference clock, as a clock name. When omitted, the reference is the file's own private per-file timeline (appropriate when the reference is itself a clockless file).

The semantics of omitting clock matter:

  • clock present (RELATE): the file keeps using its own clocks; the override only adds the missing relation between the named clock and the reference. Use this for internally-clocked traces (Perfetto proto, systrace, and so on).
  • clock omitted (PIN): the file is treated as clockless. Its events are placed on its own private per-file timeline, which the override pins to the reference. Use this for formats without absolute clocks (Chrome JSON, Gecko, Instruments). Pinning a file which then turns out to emit its own clock snapshots is an error.

WARNING: a manual offset_ns that moves events before the start of the merged timeline causes those events to be dropped, counted in the trace_sorter_negative_timestamp_dropped stat. The Perfetto UI's merge dialog reports this before opening.

attributes

Arbitrary key/value pairs annotating the archive: a benchmark name, a run id, a build id, and so on. Each entry becomes a manifest_attribute.<key> row of the metadata table.

The namespace is deliberately separate from trace_attribute.* (TraceAttributes): those are properties recorded in a trace itself, while manifest attributes describe the archive as a whole.

{
  "perfetto_manifest": {
    "version": 1,
    "attributes": {"benchmark": "startup", "run_id": 42}
  }
}

Values must be strings or integers; keys must be non-empty and should be namespaced (e.g. myapp.build_id) to avoid collisions between tools. Setting the same key twice overwrites: the last value wins.

Clock names

Wherever a clock name is expected, one of:

REALTIME, REALTIME_COARSE, MONOTONIC, MONOTONIC_COARSE, MONOTONIC_RAW, BOOTTIME

These correspond to the builtin clocks in builtin_clock.proto and the POSIX clock_gettime domains of the same names.

Effects on the SQL surface

After import, the manifest's effects are visible in the trace:

  • Every named machine gets a row in the machine table with its name set. Manifest machines get synthetic raw_id values starting at 2^32, deliberately outside the 32-bit space of ids embedded in trace packets.
  • trace_time sets the trace_time_clock_id key in the metadata table.
  • Every attributes entry becomes a manifest_attribute.<key> row in the metadata table.
  • Every clocks override is recorded as an edge in the clock_snapshot table, alongside the snapshots read from the traces themselves.
  • Each input file has a row in the trace_file table; stats and metadata rows carry machine_id and trace_id columns identifying which machine and file they describe.

Errors

The manifest is validated up front; any violation fails the whole import with an error prefixed by perfetto_manifest:. The conditions:

ConditionError
Missing versionmissing required field: version
version is not 1unsupported version: N. Only version 1 is supported
Unknown clock nameunknown clock name: X. Use one of REALTIME, ...
Second manifest in one inputmultiple perfetto_manifest files in archive
Manifest after a trace file in a concatenated streamperfetto_manifest file must be the first trace file in the input
machine and machines on the same entrymachine and machines are mutually exclusive
attributes is not an objectattributes must be an object of string or integer values
attributes value is not a string or integerattributes: 'X' must be a string or an integer
Empty attributes keyattributes: keys must be non-empty
Empty machine namemachine: name must be non-empty
machines id outside [0, 4294967295]machines: id must be in [0, 4294967295]
Packet from an embedded machine id not declared in machinesundeclared machine id N
machine on a file that is multi-machinereported when the file's packets are parsed
clocks without sync_toclocks: a sync_to block is required
sync_to without fileclocks: sync_to.file is required
sync_to.file not in filessync_to.file names unknown file 'X'. It must match the path of an entry in the files array
sync_to.machine without filea machine name alone is ambiguous, name the file too
Reference file is multi-machine but sync_to.machine missing'X' is a multi-machine trace; also name the machine
sync_to.machine not declared by that file'X' is not a machine declared by file 'Y'
This file is multi-machine but clocks.machine missingfile 'X' is a multi-machine trace; name which machine the clock is on
offset_ns not an integer / INT64_MINoffset_ns must be an integer / offset_ns is out of range
Override on a file that is itself an archive or manifestrejected
Pinning override on a file that emits clock snapshotsclock overrides require the trace to use a single clock

The authoritative definition of the format is the reader in perfetto_manifest_reader.cc and its test suite in trace_manifest/tests.py.

Next steps