Writing TrackEvent Protos Synthetically
This page acts as a reference guide to synthetically generate TrackEvent, Perfetto's native protobuf based tracing format. This allows using Perfetto's analysis and visualzation without using collecting traces using the Perfetto SDK.
TrackEvent protos can be manually written using the official protobuf library or any other protobuf-compatible library. To be language-agnostic, the rest of this page will show examples using the text format representation of protobufs.
The root container of the protobuf-based traces is the Trace message which itself is simply a repeated field of TracePacket messages.
Thread-scoped (sync) slices
NOTE: in the legacy JSON tracing format, this section correspond to B/E/I/X events with the associated M (metadata) events.
Thread scoped slices are used to trace execution of functions on a single thread. As only one function runs on a single thread over time, this requires that child slices nest perfectly inside parent slices and do not partially overlap.
This is corresponds to the following protos:
packet {
track_descriptor: {
uuid: 894893984
process: {
pid: 1234
process_name: "My process name"
}
}
}
packet {
track_descriptor: {
uuid: 49083589894
parent_uuid: 894893984
thread: {
pid: 1234
tid: 5678
thread_name: "My thread name"
}
}
}
packet {
timestamp: 200
track_event: {
type: TYPE_SLICE_BEGIN
track_uuid: 49083589894
name: "My special parent"
}
trusted_packet_sequence_id: 3903809
}
packet {
timestamp: 250
track_event: {
type: TYPE_SLICE_BEGIN
track_uuid: 49083589894
name: "My special child"
}
trusted_packet_sequence_id: 3903809
}
packet {
timestamp: 285
track_event {
type: TYPE_INSTANT
track_uuid: 49083589894
}
trusted_packet_sequence_id: 3903809
}
packet {
timestamp: 290
track_event: {
type: TYPE_SLICE_END
track_uuid: 49083589894
}
trusted_packet_sequence_id: 3903809
}
packet {
timestamp: 300
track_event: {
type: TYPE_SLICE_END
track_uuid: 49083589894
}
trusted_packet_sequence_id: 3903809
}
Process-scoped (async) slices
NOTE: in the legacy JSON tracing format, this section corresponds to b/e/n events with the associated M (metadata) events.
Process-scoped slices are useful to trace execution of a "piece of work" across multiple threads of a process. A process-scoped slice can start on a thread A and end on a thread B. Examples include work submitted to thread pools and coroutines.
Process tracks can be named corresponding to the executor and can also have child slices in an identical way to thread-scoped slices. Importantly, this means slices on a single track must strictly nest inside each other without overlapping.
As separating each track in the UI can cause a lot of clutter, the UI visually merges process tracks with the same name in each process. Note that this does not change the data model (e.g. in trace processor tracks remain separated) as this is simply a visual grouping.
This is corresponds to the following protos:
packet {
track_descriptor {
uuid: 48948
name: "My special track"
process {
pid: 1234
process_name: "My process name"
}
}
}
packet {
timestamp: 200
track_event {
type: TYPE_SLICE_BEGIN
track_uuid: 48948
name: "My special parent A"
}
trusted_packet_sequence_id: 3903809
}
packet {
timestamp: 250
track_event {
type: TYPE_SLICE_BEGIN
track_uuid: 48948
name: "My special child"
}
trusted_packet_sequence_id: 3903809
}
packet {
timestamp: 290
track_event {
type: TYPE_SLICE_END
track_uuid: 48948
}
trusted_packet_sequence_id: 3903809
}
packet {
timestamp: 300
track_event {
type: TYPE_SLICE_END
track_uuid: 48948
}
trusted_packet_sequence_id: 3903809
}
packet {
track_descriptor {
uuid: 2390190934
name: "My special track"
parent_uuid: 48948
}
}
packet {
timestamp: 230
track_event {
type: TYPE_SLICE_BEGIN
track_uuid: 2390190934
name: "My special parent A"
}
trusted_packet_sequence_id: 3903809
}
packet {
timestamp: 260
track_event {
type: TYPE_SLICE_BEGIN
track_uuid: 2390190934
name: "My special child"
}
trusted_packet_sequence_id: 3903809
}
packet {
timestamp: 270
track_event {
type: TYPE_SLICE_END
track_uuid: 2390190934
}
trusted_packet_sequence_id: 3903809
}
packet {
timestamp: 295
track_event {
type: TYPE_SLICE_END
track_uuid: 2390190934
}
trusted_packet_sequence_id: 3903809
}
Flows
NOTE: in the legacy JSON tracing format, this section correspond to s/t/f events.
Flows allow connecting any number of slices with arrows. The semantic meaning of the arrow varies across different applications but most commonly it is used to track work passing between threads or processes: e.g. the UI thread asks a background thread to do some work and notify when the result is available.
NOTE: a single flow cannot fork ands imply represents a single stream of arrows from one slice to the next. See this comment for information.
packet {
track_descriptor {
uuid: 93094
thread {
pid: 100
tid: 100
thread_name: "Main thread"
}
}
}
packet {
timestamp: 200
track_event {
type: TYPE_SLICE_BEGIN
track_uuid: 93094
name: "Request generation"
flow_ids: 1055895987
}
trusted_packet_sequence_id: 3903809
}
packet {
timestamp: 300
track_event {
type: TYPE_SLICE_END
track_uuid: 93094
}
trusted_packet_sequence_id: 3903809
}
packet {
timestamp: 400
track_event {
type: TYPE_SLICE_BEGIN
track_uuid: 93094
name: "Process background result"
flow_ids: 1055895987
}
trusted_packet_sequence_id: 3903809
}
packet {
timestamp: 500
track_event {
type: TYPE_SLICE_END
track_uuid: 93094
}
trusted_packet_sequence_id: 3903809
}
packet {
track_descriptor {
uuid: 40489498
thread {
pid: 100
tid: 101
thread_name: "Background thread"
}
}
}
packet {
timestamp: 310
track_event {
type: TYPE_SLICE_BEGIN
track_uuid: 40489498
name: "Background work"
flow_ids: 1055895987
}
trusted_packet_sequence_id: 3903809
}
packet {
timestamp: 385
track_event {
type: TYPE_SLICE_END
track_uuid: 40489498
}
trusted_packet_sequence_id: 3903809
}
Counters
NOTE: in the legacy JSON tracing format, this section correspond to C events.
Counters are useful to represent continuous values which change with time. Common examples include CPU frequency, memory usage, battery charge etc.
This corresponds to the following protos:
packet {
track_descriptor {
uuid: 1388
process {
pid: 1024
process_name: "MySpecialProcess"
}
}
}
packet {
track_descriptor {
uuid: 4489498
parent_uuid: 1388
name: "My special counter"
counter {}
}
}
packet {
timestamp: 200
track_event {
type: TYPE_COUNTER
track_uuid: 4489498
counter_value: 34567
}
trusted_packet_sequence_id: 3903809
}
packet {
timestamp: 250
track_event {
type: TYPE_COUNTER
track_uuid: 4489498
counter_value: 67890
}
trusted_packet_sequence_id: 3903809
}
packet {
timestamp: 300
track_event {
type: TYPE_COUNTER
track_uuid: 4489498
counter_value: 12345
}
trusted_packet_sequence_id: 3903809
}
packet {
timestamp: 400
track_event {
type: TYPE_COUNTER
track_uuid: 4489498
counter_value: 12345
}
trusted_packet_sequence_id: 3903809
}