xref: /aosp_15_r20/external/perfetto/docs/concepts/clock-sync.md (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1*6dbdd20aSAndroid Build Coastguard Worker# Synchronization of multiple clock domains
2*6dbdd20aSAndroid Build Coastguard Worker
3*6dbdd20aSAndroid Build Coastguard WorkerAs per [6756fb05][6756fb05] Perfetto handles events using different
4*6dbdd20aSAndroid Build Coastguard Workerclock domains. On top of the default set of builtin clock domains, new clock
5*6dbdd20aSAndroid Build Coastguard Workerdomains can be dynamically created at trace-time.
6*6dbdd20aSAndroid Build Coastguard Worker
7*6dbdd20aSAndroid Build Coastguard WorkerClock domains are allowed to drift from each other.
8*6dbdd20aSAndroid Build Coastguard WorkerAt import time, Perfetto's [Trace Processor](/docs/analysis/trace-processor.md) is able
9*6dbdd20aSAndroid Build Coastguard Workerto rebuild the clock graph and use that to re-synchronize events on a global
10*6dbdd20aSAndroid Build Coastguard Workertrace time, as long as the [ClockSnapshot][clock_snapshot] packets are present in
11*6dbdd20aSAndroid Build Coastguard Workerthe trace.
12*6dbdd20aSAndroid Build Coastguard Worker
13*6dbdd20aSAndroid Build Coastguard Worker## Problem statement
14*6dbdd20aSAndroid Build Coastguard Worker
15*6dbdd20aSAndroid Build Coastguard WorkerIn a complex multi-producer scenario, different data source can emit events
16*6dbdd20aSAndroid Build Coastguard Workerusing different clock domains.
17*6dbdd20aSAndroid Build Coastguard Worker
18*6dbdd20aSAndroid Build Coastguard WorkerSome examples:
19*6dbdd20aSAndroid Build Coastguard Worker
20*6dbdd20aSAndroid Build Coastguard Worker* On Linux/Android, Ftrace events are emitted using the `CLOCK_BOOTTIME` clock,
21*6dbdd20aSAndroid Build Coastguard Worker  but the Android event log uses `CLOCK_REALTIME`.
22*6dbdd20aSAndroid Build Coastguard Worker  Some other data sources can use `CLOCK_MONOTONIC`.
23*6dbdd20aSAndroid Build Coastguard Worker  These clocks can drift over time from each other due to suspend/resume.
24*6dbdd20aSAndroid Build Coastguard Worker
25*6dbdd20aSAndroid Build Coastguard Worker* Graphics-related events are typically timestamped by the GPU, which can use a
26*6dbdd20aSAndroid Build Coastguard Worker  hardware clock source that drifts from the system clock.
27*6dbdd20aSAndroid Build Coastguard Worker
28*6dbdd20aSAndroid Build Coastguard WorkerAt trace-time, the data sources might not be able to use `CLOCK_BOOTTIME` (or
29*6dbdd20aSAndroid Build Coastguard Workereven when possible, doing so might be prohibitively expensive).
30*6dbdd20aSAndroid Build Coastguard Worker
31*6dbdd20aSAndroid Build Coastguard WorkerTo solve this, we allow events to be recorded with different clock domains and
32*6dbdd20aSAndroid Build Coastguard Workerre-synchronize them at import time using clock snapshots.
33*6dbdd20aSAndroid Build Coastguard Worker
34*6dbdd20aSAndroid Build Coastguard Worker## Trace proto syntax
35*6dbdd20aSAndroid Build Coastguard Worker
36*6dbdd20aSAndroid Build Coastguard WorkerClock synchronization is based on two elements of the trace:
37*6dbdd20aSAndroid Build Coastguard Worker
38*6dbdd20aSAndroid Build Coastguard Worker1. [The timestamp_clock_id field of TracePacket](#timestamp_clock_id)
39*6dbdd20aSAndroid Build Coastguard Worker2. [The ClockSnapshot trace packet](#clock_snapshot)
40*6dbdd20aSAndroid Build Coastguard Worker
41*6dbdd20aSAndroid Build Coastguard Worker### {#timestamp_clock_id} The timestamp_clock_id field of TracePacket
42*6dbdd20aSAndroid Build Coastguard Worker
43*6dbdd20aSAndroid Build Coastguard Worker```protobuf
44*6dbdd20aSAndroid Build Coastguard Workermessage TracePacket {
45*6dbdd20aSAndroid Build Coastguard Worker  optional uint64 timestamp = 8;
46*6dbdd20aSAndroid Build Coastguard Worker
47*6dbdd20aSAndroid Build Coastguard Worker  // Specifies the ID of the clock used for the TracePacket |timestamp|. Can be
48*6dbdd20aSAndroid Build Coastguard Worker  // one of the built-in types from ClockSnapshot::BuiltinClocks, or a
49*6dbdd20aSAndroid Build Coastguard Worker  // producer-defined clock id.
50*6dbdd20aSAndroid Build Coastguard Worker  // If unspecified it defaults to BuiltinClocks::BOOTTIME.
51*6dbdd20aSAndroid Build Coastguard Worker  optional uint32 timestamp_clock_id = 58;
52*6dbdd20aSAndroid Build Coastguard Worker
53*6dbdd20aSAndroid Build Coastguard Worker```
54*6dbdd20aSAndroid Build Coastguard Worker
55*6dbdd20aSAndroid Build Coastguard WorkerThis (optional) field determines the clock domain for the packet.
56*6dbdd20aSAndroid Build Coastguard WorkerIf omitted it refers to the default clock domain of the trace
57*6dbdd20aSAndroid Build Coastguard Worker(`CLOCK_BOOTTIME` for Linux/Android).
58*6dbdd20aSAndroid Build Coastguard WorkerIt present, this field can be set to either:
59*6dbdd20aSAndroid Build Coastguard Worker
60*6dbdd20aSAndroid Build Coastguard Worker* One of the [builtin clocks defined in clock_snapshot.proto][builtin_clocks]
61*6dbdd20aSAndroid Build Coastguard Worker  (e.g., `CLOCK_BOOTTIME`, `CLOCK_REALTIME`, `CLOCK_MONOTONIC`). These clocks
62*6dbdd20aSAndroid Build Coastguard Worker  have an ID <= 63.
63*6dbdd20aSAndroid Build Coastguard Worker* A custom sequence-scoped clock, with 64 <= ID < 128
64*6dbdd20aSAndroid Build Coastguard Worker* A custom globally-scoped clock, with 128 <= ID < 2**32
65*6dbdd20aSAndroid Build Coastguard Worker
66*6dbdd20aSAndroid Build Coastguard Worker#### Builtin clocks
67*6dbdd20aSAndroid Build Coastguard WorkerBuiltin clocks cover the most common case of data sources using one of the
68*6dbdd20aSAndroid Build Coastguard WorkerPOSIX clocks (see `man clock_gettime`). These clocks are periodically
69*6dbdd20aSAndroid Build Coastguard Workersnapshotted by the `traced` service. The producer doesn't need to do anything
70*6dbdd20aSAndroid Build Coastguard Workerother than set the `timestamp_clock_id` field in order to emit events
71*6dbdd20aSAndroid Build Coastguard Workerthat use these clocks.
72*6dbdd20aSAndroid Build Coastguard Worker
73*6dbdd20aSAndroid Build Coastguard Worker#### Sequence-scoped clocks
74*6dbdd20aSAndroid Build Coastguard WorkerSequence-scoped clocks are application-defined clock domains that are valid only
75*6dbdd20aSAndroid Build Coastguard Workerwithin the sequence of TracePacket(s) written by the same `TraceWriter`
76*6dbdd20aSAndroid Build Coastguard Worker(i.e. TracePacket that have the same `trusted_packet_sequence_id` field).
77*6dbdd20aSAndroid Build Coastguard WorkerIn most cases this really means *"events emitted by the same data source on
78*6dbdd20aSAndroid Build Coastguard Workerthe same thread"*.
79*6dbdd20aSAndroid Build Coastguard Worker
80*6dbdd20aSAndroid Build Coastguard WorkerThis covers the most common use case of a clock domain that is used only within
81*6dbdd20aSAndroid Build Coastguard Workera data source and not shared across different data sources.
82*6dbdd20aSAndroid Build Coastguard WorkerThe main advantage of sequence-scoped clocks is that avoids the ID
83*6dbdd20aSAndroid Build Coastguard Workerdisambiguation problem and JustWorks&trade; for the most simple case.
84*6dbdd20aSAndroid Build Coastguard Worker
85*6dbdd20aSAndroid Build Coastguard WorkerIn order to make use of a custom sequence-scoped clock domain a data source
86*6dbdd20aSAndroid Build Coastguard Workermust:
87*6dbdd20aSAndroid Build Coastguard Worker
88*6dbdd20aSAndroid Build Coastguard Worker* Emit its packets with a `timestamp_clock_id` in the range [64, 127]
89*6dbdd20aSAndroid Build Coastguard Worker* Emit at least once a [`ClockSnapshot`][clock_snapshot] packet.
90*6dbdd20aSAndroid Build Coastguard Worker
91*6dbdd20aSAndroid Build Coastguard WorkerSuch `ClockSnapshot`:
92*6dbdd20aSAndroid Build Coastguard Worker
93*6dbdd20aSAndroid Build Coastguard Worker* Must be emitted on the same sequence (i.e. by the same `TraceWriter`) that is
94*6dbdd20aSAndroid Build Coastguard Worker  used to emit other `TracePacket`(s) that refer to such `timestamp_clock_id`.
95*6dbdd20aSAndroid Build Coastguard Worker* Must be emitted before the custom clock is referred to by any `TracePacket`
96*6dbdd20aSAndroid Build Coastguard Worker  written by the same `TraceWriter`.
97*6dbdd20aSAndroid Build Coastguard Worker* Must contain a snapshot of: (i) the custom clock id [64, 127] and (ii) another
98*6dbdd20aSAndroid Build Coastguard Worker  clock domain that can be resolved, at import time, against the default trace
99*6dbdd20aSAndroid Build Coastguard Worker  clock domain (`CLOCK_BOOTTIME`) (see the [Operation section](#operation)
100*6dbdd20aSAndroid Build Coastguard Worker  below).
101*6dbdd20aSAndroid Build Coastguard Worker
102*6dbdd20aSAndroid Build Coastguard WorkerCollisions of `timestamp_clock_id` across two different `TraceWriter` sequences
103*6dbdd20aSAndroid Build Coastguard Workerare okay. E.g., two data sources, unaware of each other, can both use clock ID
104*6dbdd20aSAndroid Build Coastguard Worker64 to refer to two different clock domains.
105*6dbdd20aSAndroid Build Coastguard Worker
106*6dbdd20aSAndroid Build Coastguard Worker#### Globally-scoped clocks
107*6dbdd20aSAndroid Build Coastguard WorkerGlobally-scoped clock domains work similarly to sequence-scoped clock domains,
108*6dbdd20aSAndroid Build Coastguard Workerwith the only difference that their scope is global and applies to all
109*6dbdd20aSAndroid Build Coastguard Worker`TracePacket`(s) of the trace.
110*6dbdd20aSAndroid Build Coastguard Worker
111*6dbdd20aSAndroid Build Coastguard WorkerThe same `ClockSnapshot` rules as above apply. The only difference is that once
112*6dbdd20aSAndroid Build Coastguard Workera `ClockSnapshot` defines a clock domain with ID >= 128, that clock domain can
113*6dbdd20aSAndroid Build Coastguard Workerbe referred to by any `TracePacket` written by any `TraceWriter` sequence.
114*6dbdd20aSAndroid Build Coastguard Worker
115*6dbdd20aSAndroid Build Coastguard WorkerCare must be taken to avoid collisions between global clock domains defined by
116*6dbdd20aSAndroid Build Coastguard Workerdifferent data sources unaware of each other.
117*6dbdd20aSAndroid Build Coastguard Worker
118*6dbdd20aSAndroid Build Coastguard WorkerAs such, it is **strongly discouraged** to just use the ID 128 (or any other
119*6dbdd20aSAndroid Build Coastguard Workerarbitrarily chosen value). Instead the recommended pattern is:
120*6dbdd20aSAndroid Build Coastguard Worker
121*6dbdd20aSAndroid Build Coastguard Worker* Chose a fully qualified name for the clock domain
122*6dbdd20aSAndroid Build Coastguard Worker  (e.g. `com.example.my_subsystem`)
123*6dbdd20aSAndroid Build Coastguard Worker* Chose the clock ID as `HASH("com.example.my_subsystem") | 0x80000000`
124*6dbdd20aSAndroid Build Coastguard Worker  where `HASH(x)` is the FNV-1a hash of the fully qualified clock domain name.
125*6dbdd20aSAndroid Build Coastguard Worker
126*6dbdd20aSAndroid Build Coastguard Worker### {#clock_snapshot} The ClockSnapshot trace packet
127*6dbdd20aSAndroid Build Coastguard Worker
128*6dbdd20aSAndroid Build Coastguard WorkerThe [`ClockSnapshot`][clock_snapshot] packet defines sync points between two or
129*6dbdd20aSAndroid Build Coastguard Workermore clock domains. It conveys the notion *"at this point in time, the timestamp
130*6dbdd20aSAndroid Build Coastguard Workerof the clock domains X,Y,Z was 1000, 2000, 3000."*.
131*6dbdd20aSAndroid Build Coastguard Worker
132*6dbdd20aSAndroid Build Coastguard WorkerThe trace importer ([Trace Processor](/docs/analysis/trace-processor.md)) uses this
133*6dbdd20aSAndroid Build Coastguard Workerinformation to establish a mapping between these clock domain. For instance,
134*6dbdd20aSAndroid Build Coastguard Workerto realize that 1042 on clock domain X == 3042 on clock domain Z.
135*6dbdd20aSAndroid Build Coastguard Worker
136*6dbdd20aSAndroid Build Coastguard WorkerThe `traced` service automatically emits `ClockSnapshot` packets for the builtin
137*6dbdd20aSAndroid Build Coastguard Workerclock domains on a regular basis.
138*6dbdd20aSAndroid Build Coastguard Worker
139*6dbdd20aSAndroid Build Coastguard WorkerA data source should emit `ClockSnapshot` packets only when using custom clock
140*6dbdd20aSAndroid Build Coastguard Workerdomains, either sequence-scoped or globally-scoped.
141*6dbdd20aSAndroid Build Coastguard Worker
142*6dbdd20aSAndroid Build Coastguard WorkerIt is *not* mandatory that the `ClockSnapshot` for a custom clock domain
143*6dbdd20aSAndroid Build Coastguard Workercontains also a snapshot of `CLOCK_BOOTTIME` (although it is advisable to do
144*6dbdd20aSAndroid Build Coastguard Workerso when possible). The Trace Processor can deal with multi-path clock domain
145*6dbdd20aSAndroid Build Coastguard Workerresolution based on graph traversal (see the [Operation](#operation) section).
146*6dbdd20aSAndroid Build Coastguard Worker
147*6dbdd20aSAndroid Build Coastguard Worker## Operation
148*6dbdd20aSAndroid Build Coastguard Worker
149*6dbdd20aSAndroid Build Coastguard WorkerAt import time Trace Processor will attempt to convert the timestamp of each
150*6dbdd20aSAndroid Build Coastguard WorkerTracePacket down to the trace clock domain (`CLOCK_BOOTTIME`) using the
151*6dbdd20aSAndroid Build Coastguard Worker`ClockSnapshot` packets seen until then using nearest neighbor approximation.
152*6dbdd20aSAndroid Build Coastguard Worker
153*6dbdd20aSAndroid Build Coastguard WorkerFor instance, assume that the trace contains `ClockSnapshot` for
154*6dbdd20aSAndroid Build Coastguard Worker`CLOCK_BOOTTIME` and `CLOCK_MONOTONIC` as follows:
155*6dbdd20aSAndroid Build Coastguard Worker
156*6dbdd20aSAndroid Build Coastguard Worker```python
157*6dbdd20aSAndroid Build Coastguard WorkerCLOCK_MONOTONIC     1000    1100   1200   1900  ...  2000   2100
158*6dbdd20aSAndroid Build Coastguard WorkerCLOCK_BOOTTIME      2000    2100   2200   2900  ...  3500   3600
159*6dbdd20aSAndroid Build Coastguard Worker```
160*6dbdd20aSAndroid Build Coastguard Worker
161*6dbdd20aSAndroid Build Coastguard WorkerIn this example `CLOCK_MONOTONIC` is 1000 ns ahead of `CLOCK_BOOTTIME` until
162*6dbdd20aSAndroid Build Coastguard WorkerT=2900. Then the two clocks go out of sync (e.g. the device is suspended) and,
163*6dbdd20aSAndroid Build Coastguard Workeron the next snapshot, the two clocks are 1500 ns apart.
164*6dbdd20aSAndroid Build Coastguard Worker
165*6dbdd20aSAndroid Build Coastguard WorkerIf a `TracePacket` with `timestamp_clock_id=CLOCK_MONOTONIC` and
166*6dbdd20aSAndroid Build Coastguard Worker`timestamp=1104` is seen, the clock sync logic will:
167*6dbdd20aSAndroid Build Coastguard Worker
168*6dbdd20aSAndroid Build Coastguard Worker1. Find the latest snapshot for `CLOCK_MONOTONIC` <= 1104 (in the example above
169*6dbdd20aSAndroid Build Coastguard Worker   the 2nd one with `CLOCK_MONOTONIC=1100`)
170*6dbdd20aSAndroid Build Coastguard Worker2. Compute the clock domain conversion to `CLOCK_BOOTTIME` by applying the
171*6dbdd20aSAndroid Build Coastguard Worker   delta (1104 - 1100) to the corresponding `CLOCK_BOOTTIME` snapshot
172*6dbdd20aSAndroid Build Coastguard Worker   (2100, so 2100 + (1104 - 1100) -> 2104).
173*6dbdd20aSAndroid Build Coastguard Worker
174*6dbdd20aSAndroid Build Coastguard WorkerThe example above is rather simple, because the source clock domain  (i.e. the
175*6dbdd20aSAndroid Build Coastguard Workerone specified by the `timestamp_clock_id` field) and the target clock domain
176*6dbdd20aSAndroid Build Coastguard Worker(i.e. the trace time, `CLOCK_BOTTIME`) are snapshotted within the same
177*6dbdd20aSAndroid Build Coastguard Worker`ClockSnapshot` packets.
178*6dbdd20aSAndroid Build Coastguard Worker
179*6dbdd20aSAndroid Build Coastguard WorkerClock domain conversion is possible also in more complex scenarios where the
180*6dbdd20aSAndroid Build Coastguard Workertwo domains are not directly connected, as long as a path exist between the two.
181*6dbdd20aSAndroid Build Coastguard Worker
182*6dbdd20aSAndroid Build Coastguard WorkerIn this sense `ClockSnapshot` packets define edges of an acyclic graph that is
183*6dbdd20aSAndroid Build Coastguard Workerqueried to perform clock domain conversions. All types of clock domains can be
184*6dbdd20aSAndroid Build Coastguard Workerused in the graph search.
185*6dbdd20aSAndroid Build Coastguard Worker
186*6dbdd20aSAndroid Build Coastguard WorkerIn the more general case, the clock domain conversion logic operates as follows:
187*6dbdd20aSAndroid Build Coastguard Worker
188*6dbdd20aSAndroid Build Coastguard Worker* The shortest path between the source and target clock domains is identified,
189*6dbdd20aSAndroid Build Coastguard Worker  using a breadth first search in the graph.
190*6dbdd20aSAndroid Build Coastguard Worker* For each clock domain of the path identified, the timestamp is converted using
191*6dbdd20aSAndroid Build Coastguard Worker  the aforementioned nearest neighbor resolution.
192*6dbdd20aSAndroid Build Coastguard Worker
193*6dbdd20aSAndroid Build Coastguard WorkerThis allows to deal with complex scenarios as follows:
194*6dbdd20aSAndroid Build Coastguard Worker
195*6dbdd20aSAndroid Build Coastguard Worker```python
196*6dbdd20aSAndroid Build Coastguard WorkerCUSTOM_CLOCK        1000                 3000
197*6dbdd20aSAndroid Build Coastguard WorkerCLOCK_MONOTONIC     1100       1200      3200          4000
198*6dbdd20aSAndroid Build Coastguard WorkerCLOCK_BOOTTIME                 5200                    9000
199*6dbdd20aSAndroid Build Coastguard Worker```
200*6dbdd20aSAndroid Build Coastguard Worker
201*6dbdd20aSAndroid Build Coastguard WorkerIn the example above, there is no snapshot that directly links `CUSTOM_CLOCK`
202*6dbdd20aSAndroid Build Coastguard Workerand `CLOCK_BOOTTIME`. However there is an indirect path that allows a conversion
203*6dbdd20aSAndroid Build Coastguard Workervia `CUSTOM_CLOCK -> CLOCK_MONOTONIC -> CLOCK_BOOTTIME`.
204*6dbdd20aSAndroid Build Coastguard Worker
205*6dbdd20aSAndroid Build Coastguard WorkerThis allows to synchronize a hypothetical `TracePacket` that has
206*6dbdd20aSAndroid Build Coastguard Worker`timestamp_clock_id=CUSTOM_CLOCK` and `timestamp=3503` as follows:
207*6dbdd20aSAndroid Build Coastguard Worker
208*6dbdd20aSAndroid Build Coastguard Worker```python
209*6dbdd20aSAndroid Build Coastguard Worker#Step 1
210*6dbdd20aSAndroid Build Coastguard WorkerCUSTOM_CLOCK = 3503
211*6dbdd20aSAndroid Build Coastguard WorkerNearest snapshot: {CUSTOM_CLOCK:3000, CLOCK_MONOTONIC:3200}
212*6dbdd20aSAndroid Build Coastguard WorkerCLOCK_MONOTONIC = (3503 - 3000) + 3200 = 3703
213*6dbdd20aSAndroid Build Coastguard Worker
214*6dbdd20aSAndroid Build Coastguard Worker#Step 2
215*6dbdd20aSAndroid Build Coastguard WorkerCLOCK_MONOTONIC = 3703
216*6dbdd20aSAndroid Build Coastguard WorkerNearest snapshot: {CLOCK_MONOTONIC:1200, CLOCK_BOOTTIME:5200}
217*6dbdd20aSAndroid Build Coastguard WorkerCLOCK_BOOTTIME = (3703 - 1200) + 5200 = 7703
218*6dbdd20aSAndroid Build Coastguard Worker```
219*6dbdd20aSAndroid Build Coastguard Worker
220*6dbdd20aSAndroid Build Coastguard Worker## Caveats
221*6dbdd20aSAndroid Build Coastguard Worker
222*6dbdd20aSAndroid Build Coastguard WorkerClock resolution between two domains (A,B) is allowed only as long as all the
223*6dbdd20aSAndroid Build Coastguard Workerclock domains in the A -> B path are monotonic (or at least look so in the
224*6dbdd20aSAndroid Build Coastguard Worker`ClockSnapshot` packets).
225*6dbdd20aSAndroid Build Coastguard WorkerIf non-monotonicity is detected at import time, the clock domain is excluded as
226*6dbdd20aSAndroid Build Coastguard Workera source path in the graph search and is allowed only as a target path.
227*6dbdd20aSAndroid Build Coastguard Worker
228*6dbdd20aSAndroid Build Coastguard WorkerFor instance, imagine capturing a trace that has both `CLOCK_BOOTTIME`
229*6dbdd20aSAndroid Build Coastguard Workerand `CLOCK_REALTIME` in the night when daylight saving is applied, when the
230*6dbdd20aSAndroid Build Coastguard Workerreal-time clock jumps back from 3AM to 2AM.
231*6dbdd20aSAndroid Build Coastguard Worker
232*6dbdd20aSAndroid Build Coastguard WorkerSuch a trace would contain several snapshots that break bijectivity between the
233*6dbdd20aSAndroid Build Coastguard Workertwo clock domains. In this case converting a `CLOCK_BOOTTIME` timestamp to
234*6dbdd20aSAndroid Build Coastguard Worker`CLOCK_REALTIME` is always possible without ambiguities (eventually two distinct
235*6dbdd20aSAndroid Build Coastguard Workertimestamps can be resolved against the same `CLOCK_REALTIME` timestamp).
236*6dbdd20aSAndroid Build Coastguard WorkerThe opposite is not allowed, because `CLOCK_REALTIME` timestamps between 2AM
237*6dbdd20aSAndroid Build Coastguard Workerand 3AM are ambiguous and could be resolved against two different
238*6dbdd20aSAndroid Build Coastguard Worker`CLOCK_BOOTTIME` timestamps).
239*6dbdd20aSAndroid Build Coastguard Worker
240*6dbdd20aSAndroid Build Coastguard Worker[6756fb05]: https://android-review.googlesource.com/c/platform/external/perfetto/+/1101915/
241*6dbdd20aSAndroid Build Coastguard Worker[clock_snapshot]: https://android.googlesource.com/platform/external/perfetto/+/refs/heads/main/protos/perfetto/trace/clock_snapshot.proto
242*6dbdd20aSAndroid Build Coastguard Worker[timestamp_clock_id]: https://android.googlesource.com/platform/external/perfetto/+/3e7ca4f5893f7d762ec24a2eac9a47343b226c6c/protos/perfetto/trace/trace_packet.proto#68
243*6dbdd20aSAndroid Build Coastguard Worker[builtin_clocks]: https://android.googlesource.com/platform/external/perfetto/+/3e7ca4f5893f7d762ec24a2eac9a47343b226c6c/protos/perfetto/trace/clock_snapshot.proto#25
244