• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Writing TrackEvent Protos Synthetically
2This page acts as a reference guide to synthetically generate TrackEvent,
3Perfetto's native protobuf based tracing format. This allows using Perfetto's
4analysis and visualzation without using collecting traces using the Perfetto
5SDK.
6
7TrackEvent protos can be manually written using the
8[official protobuf library](https://protobuf.dev/reference/) or any other
9protobuf-compatible library. To be language-agnostic, the rest of this page
10will show examples using the
11[text format](https://protobuf.dev/reference/protobuf/textformat-spec/)
12representation of protobufs.
13
14The root container of the protobuf-based traces is the
15[Trace](https://cs.android.com/android/platform/superproject/main/+/main:external/perfetto/protos/perfetto/trace/trace.proto)
16message which itself is simply a repeated field of
17[TracePacket](https://cs.android.com/android/platform/superproject/main/+/main:external/perfetto/protos/perfetto/trace/trace_packet.proto)
18messages.
19
20## Thread-scoped (sync) slices
21NOTE: in the legacy JSON tracing format, this section correspond to B/E/I/X
22events with the associated M (metadata) events.
23
24Thread scoped slices are used to trace execution of functions on a single
25thread. As only one function runs on a single thread over time, this requires
26that child slices nest perfectly inside parent slices and do not partially
27overlap.
28
29![Thread track event in UI](/docs/images/synthetic-track-event-thread.png)
30
31This is corresponds to the following protos:
32```
33# Emit this packet once *before* you emit the first event for this process.
34packet {
35  track_descriptor: {
36    uuid: 894893984                     # 64-bit random number.
37    process: {
38      pid: 1234                         # PID for your process.
39      process_name: "My process name"
40    }
41  }
42}
43
44# Emit this packet once *before* you emit the first event for this thread.
45packet {
46  track_descriptor: {
47    uuid: 49083589894                   # 64-bit random number.
48    parent_uuid: 894893984              # UUID from above.
49    thread: {
50      pid: 1234                         # PID for your process.
51      tid: 5678                         # TID for your thread.
52      thread_name: "My thread name"
53    }
54  }
55}
56
57# The events for this thread.
58packet {
59  timestamp: 200
60  track_event: {
61    type: TYPE_SLICE_BEGIN
62    track_uuid: 49083589894             # Same random number from above.
63    name: "My special parent"
64  }
65  trusted_packet_sequence_id: 3903809   # Generate *once*, use throughout.
66}
67packet {
68  timestamp: 250
69  track_event: {
70    type: TYPE_SLICE_BEGIN
71    track_uuid: 49083589894
72    name: "My special child"
73  }
74  trusted_packet_sequence_id: 3903809
75}
76packet {
77  timestamp: 285
78  track_event {
79    type: TYPE_INSTANT
80    track_uuid: 49083589894
81  }
82  trusted_packet_sequence_id: 3903809
83}
84packet {
85  timestamp: 290
86  track_event: {
87    type: TYPE_SLICE_END
88    track_uuid: 49083589894
89  }
90  trusted_packet_sequence_id: 3903809
91}
92packet {
93  timestamp: 300
94  track_event: {
95    type: TYPE_SLICE_END
96    track_uuid: 49083589894
97  }
98  trusted_packet_sequence_id: 3903809
99}
100```
101
102## Process-scoped (async) slices
103NOTE: in the legacy JSON tracing format, this section corresponds to b/e/n
104events with the associated M (metadata) events.
105
106Process-scoped slices are useful to trace execution of a "piece of work" across
107multiple threads of a process. A process-scoped slice can start on a thread
108A and end on a thread B. Examples include work submitted to thread pools
109and coroutines.
110
111Process tracks can be named corresponding to the executor and can also have
112child slices in an identical way to thread-scoped slices. Importantly, this
113means slices on a single track must **strictly nest** inside each other
114without overlapping.
115
116As separating each track in the UI can cause a lot of clutter, the UI
117visually merges process tracks with the same name in each process. Note that
118this **does not** change the data model (e.g. in trace processor
119tracks remain separated) as this is simply a visual grouping.
120
121![Process track event in UI](/docs/images/synthetic-track-event-process.png)
122
123This is corresponds to the following protos:
124```
125# The first track associated with this process.
126packet {
127  track_descriptor {
128    uuid: 48948                         # 64-bit random number.
129    name: "My special track"
130    process {
131      pid: 1234                         # PID for your process
132      process_name: "My process name"
133    }
134  }
135}
136# The events for the first track.
137packet {
138  timestamp: 200
139  track_event {
140    type: TYPE_SLICE_BEGIN
141    track_uuid: 48948                   # Same random number from above.
142    name: "My special parent A"
143  }
144  trusted_packet_sequence_id: 3903809   # Generate *once*, use throughout.
145}
146packet {
147  timestamp: 250
148  track_event {
149    type: TYPE_SLICE_BEGIN
150    track_uuid: 48948
151    name: "My special child"
152  }
153  trusted_packet_sequence_id: 3903809
154}
155packet {
156  timestamp: 290
157  track_event {
158    type: TYPE_SLICE_END
159    track_uuid: 48948
160  }
161  trusted_packet_sequence_id: 3903809
162}
163packet {
164  timestamp: 300
165  track_event {
166    type: TYPE_SLICE_END
167    track_uuid: 48948
168  }
169  trusted_packet_sequence_id: 3903809
170}
171
172# The second track associated with this process. Note how we make the above
173# track the "parent" of this track: this means that this track also is
174# associated to the same process. Note further this shows as the same visual
175# track in the UI but remains separate in the trace and data model. Emitting
176# these events on a separate track is necessary because these events overlap
177# *without* nesting with the above events.
178packet {
179  track_descriptor {
180      uuid: 2390190934                  # 64-bit random number.
181      name: "My special track"
182      parent_uuid: 48948
183  }
184}
185# The events for the second track.
186packet {
187  timestamp: 230
188  track_event {
189    type: TYPE_SLICE_BEGIN
190    track_uuid: 2390190934              # Same random number from above.
191    name: "My special parent A"
192  }
193  trusted_packet_sequence_id: 3903809
194}
195packet {
196  timestamp: 260
197  track_event {
198    type: TYPE_SLICE_BEGIN
199    track_uuid: 2390190934
200    name: "My special child"
201  }
202  trusted_packet_sequence_id: 3903809
203}
204packet {
205  timestamp: 270
206  track_event {
207    type: TYPE_SLICE_END
208    track_uuid: 2390190934
209  }
210  trusted_packet_sequence_id: 3903809
211}
212packet {
213  timestamp: 295
214  track_event {
215    type: TYPE_SLICE_END
216    track_uuid: 2390190934
217  }
218  trusted_packet_sequence_id: 3903809
219}
220```
221
222## Flows
223NOTE: in the legacy JSON tracing format, this section correspond to s/t/f
224events.
225
226Flows allow connecting any number of slices with arrows. The semantic meaning
227of the arrow varies across different applications but most commonly it is used
228to track work passing between threads or processes: e.g. the UI thread asks a
229background thread to do some work and notify when the result is available.
230
231NOTE: a single flow *cannot* fork ands imply represents a single stream of
232arrows from one slice to the next. See [this](https://source.chromium.org/chromium/chromium/src/+/main:third_party/perfetto/protos/perfetto/trace/perfetto_trace.proto;drc=ba05b783d9c29fe334a02913cf157ea1d415d37c;l=9604) comment for information.
233
234![TrackEvent flows in UI](/docs/images/synthetic-track-event-flow.png)
235
236```
237# The main thread of the process.
238packet {
239  track_descriptor {
240    uuid: 93094
241    thread {
242        pid: 100
243        tid: 100
244        thread_name: "Main thread"
245    }
246  }
247}
248packet {
249  timestamp: 200
250  track_event {
251    type: TYPE_SLICE_BEGIN
252    track_uuid: 93094
253    name: "Request generation"
254    flow_ids: 1055895987                  # Random number used to track work
255                                          # across threads/processes.
256  }
257  trusted_packet_sequence_id: 3903809
258}
259packet {
260  timestamp: 300
261  track_event {
262    type: TYPE_SLICE_END
263    track_uuid: 93094
264  }
265  trusted_packet_sequence_id: 3903809
266}
267packet {
268  timestamp: 400
269  track_event {
270    type: TYPE_SLICE_BEGIN
271    track_uuid: 93094
272    name: "Process background result"
273    flow_ids: 1055895987                  # Same as above.
274  }
275  trusted_packet_sequence_id: 3903809
276}
277packet {
278  timestamp: 500
279  track_event {
280    type: TYPE_SLICE_END
281    track_uuid: 93094
282  }
283  trusted_packet_sequence_id: 3903809
284}
285
286# The background thread of the process.
287packet {
288  track_descriptor {
289    uuid: 40489498
290    thread {
291      pid: 100
292      tid: 101
293      thread_name: "Background thread"
294    }
295  }
296}
297packet {
298  timestamp: 310
299  track_event {
300    type: TYPE_SLICE_BEGIN
301    track_uuid: 40489498
302    name: "Background work"
303    flow_ids: 1055895987                  # Same as above.
304  }
305  trusted_packet_sequence_id: 3903809
306}
307packet {
308  timestamp: 385
309  track_event {
310    type: TYPE_SLICE_END
311    track_uuid: 40489498
312  }
313  trusted_packet_sequence_id: 3903809
314}
315```
316
317## Counters
318NOTE: in the legacy JSON tracing format, this section correspond to C events.
319
320Counters are useful to represent continuous values which change with time.
321Common examples include CPU frequency, memory usage, battery charge etc.
322
323![TrackEvent counter in UI](/docs/images/synthetic-track-event-counter.png)
324
325This corresponds to the following protos:
326```
327# Counter track scoped to a process.
328packet {
329  track_descriptor {
330    uuid: 1388
331    process {
332      pid: 1024
333      process_name: "MySpecialProcess"
334    }
335  }
336}
337packet {
338  track_descriptor {
339    uuid: 4489498
340    parent_uuid: 1388
341    name: "My special counter"
342    counter {}
343  }
344}
345packet {
346  timestamp: 200
347  track_event {
348    type: TYPE_COUNTER
349    track_uuid: 4489498
350    counter_value: 34567    # Value at start
351  }
352  trusted_packet_sequence_id: 3903809
353}
354packet {
355  timestamp: 250
356  track_event {
357    type: TYPE_COUNTER
358    track_uuid: 4489498
359    counter_value: 67890    # Value goes up
360  }
361  trusted_packet_sequence_id: 3903809
362}
363packet {
364  timestamp: 300
365  track_event {
366    type: TYPE_COUNTER
367    track_uuid: 4489498
368    counter_value: 12345   # Value goes down
369  }
370  trusted_packet_sequence_id: 3903809
371}
372packet {
373  timestamp: 400
374  track_event {
375    type: TYPE_COUNTER
376    track_uuid: 4489498
377    counter_value: 12345   # Final value
378  }
379  trusted_packet_sequence_id: 3903809
380}
381```
382
383## Interning
384NOTE: there is no equivalent to interning in the JSON tracing format.
385
386Interning is an advanced but powerful feature of the protobuf tracing format
387which allows allows for reducing the number of times long strings are emitted
388in the trace.
389
390Specifically, certain fields in the protobuf format allow associating an "iid"
391(interned id) to a string and using the iid to reference the string in all
392future packets. The most commonly used cases are slice names and category
393names
394
395Here is an example of a trace which makes use of interning to reduce the
396number of times a very long slice name is emitted:
397![TrackEvent interning](/docs/images/synthetic-track-event-interned.png)
398
399This corresponds to the following protos:
400```
401packet {
402  track_descriptor {
403    uuid: 48948                         # 64-bit random number.
404    name: "My special track"
405    process {
406      pid: 1234                         # PID for your process
407      process_name: "My process name"
408    }
409  }
410}
411packet {
412  timestamp: 200
413  track_event {
414    type: TYPE_SLICE_BEGIN
415    track_uuid: 48948                   # Same random number from above.
416    name_iid: 1                         # References the string in interned_data
417                                        # (see below)
418  }
419  trusted_packet_sequence_id: 3903809   # Generate *once*, use throughout.
420
421  interned_data {
422    # Creates a mapping from the iid "1" to the string name: any |name_iid| field
423    # in this packet onwards will transparently be remapped to this string by trace
424    # processor.
425    # Note: iid 0 is *not* a valid IID and should not be used.
426    event_names {
427      iid: 1
428      name: "A very very very long slice name which we don't want to repeat"
429    }
430  }
431
432  first_packet_on_sequence: true        # Indicates to trace processor that
433                                        # this is the first packet on the
434                                        # sequence.
435  previous_packet_dropped: true         # Same as |first_packet_on_sequence|.
436
437  # Indicates to trace processor that this sequence resets the incremental state but
438  # also depends on incrtemental state state.
439  # 3 = SEQ_INCREMENTAL_STATE_CLEARED | SEQ_NEEDS_INCREMENTAL_STATE
440  sequence_flags: 3
441}
442packet {
443  timestamp: 201
444  track_event {
445    type: TYPE_SLICE_END
446    track_uuid: 48948
447  }
448  trusted_packet_sequence_id: 3903809
449}
450packet {
451  timestamp: 202
452  track_event {
453    type: TYPE_SLICE_BEGIN
454    track_uuid: 48948                   # Same random number from above.
455    name_iid: 1                         # References the string in interned_data
456                                        # above.
457  }
458  trusted_packet_sequence_id: 3903809   # Generate *once*, use throughout.
459  # 2 = SEQ_NEEDS_INCREMENTAL_STATE
460  sequence_flags: 2
461}
462packet {
463  timestamp: 203
464  track_event {
465    type: TYPE_SLICE_END
466    track_uuid: 48948
467  }
468  trusted_packet_sequence_id: 3903809
469}
470```
471