| # 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](/docs/analysis/trace-processor.md) |
| 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](#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](/docs/analysis/merging-traces.md); for |
| the underlying model see |
| [How trace merging works](/docs/concepts/merging-traces.md). |
| |
| 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](/docs/visualization/merging-traces.md) |
| 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 |
| |
| ```json |
| { |
| "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} 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. |
| |
| ## {#schema} Top-level fields |
| |
| The document is a JSON object with a single top-level `perfetto_manifest` |
| key, containing: |
| |
| | Field | Type | Required | Description | |
| |-------|------|----------|-------------| |
| | `version` | integer | yes | Must be `1`. Any other value is rejected. | |
| | `trace_time` | object | no | Selects the clock of the merged timeline. See [trace_time](#trace-time). | |
| | `files` | array | no | Per-file configuration entries. See [files](#files). | |
| | `attributes` | object | no | Key/value pairs annotating the archive. See [attributes](#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](/docs/concepts/merging-traces.md). |
| |
| ## {#trace-time} 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. |
| |
| | Field | Type | Required | Description | |
| |-------|------|----------|-------------| |
| | `clock` | string | yes | One of the [clock names](#clock-names). | |
| | `file` | string | no | Pins the clock to the machine of this file. Must match the `path` of an entry in `files`. | |
| | `machine` | string | no | When `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} files |
| |
| Each entry in the `files` array is an object: |
| |
| | Field | Type | Required | Description | |
| |-------|------|----------|-------------| |
| | `path` | string | yes | The exact name of a file in the archive (for TAR/ZIP, the member path). | |
| | `machine` | object | no | Attributes the whole file to a named machine. Mutually exclusive with `machines`. | |
| | `machines` | array | no | Remaps a multi-machine trace's embedded machine ids to named machines. Mutually exclusive with `machine`. | |
| | `clocks` | object | no | Manually relates this file's clock to a clock in another file. See [clocks](#clocks). | |
| |
| ### {#machine} machine |
| |
| ```json |
| {"path": "watch.pftrace", "machine": {"name": "watch"}} |
| ``` |
| |
| | Field | Type | Required | Description | |
| |-------|------|----------|-------------| |
| | `name` | string (non-empty) | yes | The 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](/docs/deployment/multi-machine-architecture.md)); use |
| `machines` for those. |
| |
| ### {#machines} machines |
| |
| ```json |
| {"path": "relay.pftrace", "machines": [ |
| {"id": 0, "name": "host"}, |
| {"id": 1234, "name": "vm"} |
| ]} |
| ``` |
| |
| | Field | Type | Required | Description | |
| |-------|------|----------|-------------| |
| | `id` | integer in [0, 4294967295] | yes | A machine id embedded in the trace's packets. | |
| | `name` | string (non-empty) | yes | The 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} 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. |
| |
| ```json |
| { |
| "path": "app_log.json", |
| "clocks": { |
| "sync_to": {"file": "phone.pftrace", "clock": "BOOTTIME"}, |
| "offset_ns": 250000000 |
| } |
| } |
| ``` |
| |
| | Field | Type | Required | Description | |
| |-------|------|----------|-------------| |
| | `clock` | string | no | Which of this file's own clocks to relate, as a [clock name](#clock-names). Omit for clockless files. | |
| | `machine` | string | no | When this file is multi-machine, names which of its machines owns the source clock. Required in that case. | |
| | `sync_to` | object | yes | The reference clock. See below. | |
| | `offset_ns` | integer | no (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: |
| |
| | Field | Type | Required | Description | |
| |-------|------|----------|-------------| |
| | `file` | string | yes | The reference file. Must match the `path` of an entry in `files`. | |
| | `machine` | string | no | When 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. | |
| | `clock` | string | no | The reference clock, as a [clock name](#clock-names). 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} 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](/protos/perfetto/common/trace_attributes.proto)): those |
| are properties recorded in a trace itself, while manifest attributes |
| describe the archive as a whole. |
| |
| ```json |
| { |
| "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} 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](/protos/perfetto/common/builtin_clock.proto) and the |
| POSIX `clock_gettime` domains of the same names. |
| |
| ## {#sql} 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`](/docs/analysis/sql-tables.autogen#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} Errors |
| |
| The manifest is validated up front; any violation fails the whole import |
| with an error prefixed by `perfetto_manifest:`. The conditions: |
| |
| | Condition | Error | |
| |-----------|-------| |
| | Missing `version` | `missing required field: version` | |
| | `version` is not 1 | `unsupported version: N. Only version 1 is supported` | |
| | Unknown clock name | `unknown clock name: X. Use one of REALTIME, ...` | |
| | Second manifest in one input | `multiple perfetto_manifest files in archive` | |
| | Manifest after a trace file in a concatenated stream | `perfetto_manifest file must be the first trace file in the input` | |
| | `machine` and `machines` on the same entry | `machine and machines are mutually exclusive` | |
| | `attributes` is not an object | `attributes must be an object of string or integer values` | |
| | `attributes` value is not a string or integer | `attributes: 'X' must be a string or an integer` | |
| | Empty `attributes` key | `attributes: keys must be non-empty` | |
| | Empty machine name | `machine: 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 `machines` | `undeclared machine id N` | |
| | `machine` on a file that is multi-machine | reported when the file's packets are parsed | |
| | `clocks` without `sync_to` | `clocks: a sync_to block is required` | |
| | `sync_to` without `file` | `clocks: sync_to.file is required` | |
| | `sync_to.file` not in `files` | `sync_to.file names unknown file 'X'. It must match the path of an entry in the files array` | |
| | `sync_to.machine` without `file` | a 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` missing | `file 'X' is a multi-machine trace; name which machine the clock is on` | |
| | `offset_ns` not an integer / INT64_MIN | `offset_ns must be an integer` / `offset_ns is out of range` | |
| | Override on a file that is itself an archive or manifest | rejected | |
| | Pinning override on a file that emits clock snapshots | `clock overrides require the trace to use a single clock` | |
| |
| The authoritative definition of the format is the reader in |
| [perfetto_manifest_reader.cc](/src/trace_processor/plugins/perfetto_manifest/perfetto_manifest_reader.cc) |
| and its test suite in |
| [trace_manifest/tests.py](/test/trace_processor/diff_tests/parser/trace_manifest/tests.py). |
| |
| ## Next steps |
| |
| - [Merging traces with Trace Processor](/docs/analysis/merging-traces.md): |
| building and querying merged archives. |
| - [Merging traces in the Perfetto UI](/docs/visualization/merging-traces.md): |
| the interactive merge dialog, which generates this format for you. |
| - [How trace merging works](/docs/concepts/merging-traces.md): machines, |
| the clock graph, and the automatic placement rules. |