1use std::collections::VecDeque;
6
7const NANOS_PER_MILLISECOND: i64 = 1_000_000;
8const TIMELINE_DRIFT_THRESHOLD_MS: TimeOffsetMillis = TimeOffsetMillis(200);
9const TIMELINE_BOOT_TIME_THRESHOLD_MS: TimeOffsetMillis = TimeOffsetMillis(200);
10const TIMELINE_MAX_SIZE: usize = 400;
11const TIMELINE_TRIM_SIZE: usize = 200;
12
13#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
15struct TimeOffsetMillis(i64);
16
17impl From<zx::BootInstant> for TimeOffsetMillis {
18 fn from(value: zx::BootInstant) -> Self {
19 Self(value.into_nanos() / NANOS_PER_MILLISECOND)
20 }
21}
22
23impl From<zx::MonotonicInstant> for TimeOffsetMillis {
24 fn from(value: zx::MonotonicInstant) -> Self {
25 Self(value.into_nanos() / NANOS_PER_MILLISECOND)
26 }
27}
28
29impl TimeOffsetMillis {
30 fn to_nanos(&self) -> i64 {
31 self.0 * NANOS_PER_MILLISECOND
32 }
33}
34
35impl std::ops::Add for TimeOffsetMillis {
36 type Output = Self;
37
38 fn add(self, rhs: Self) -> Self::Output {
39 Self(self.0 + rhs.0)
40 }
41}
42
43impl std::ops::Sub for TimeOffsetMillis {
44 type Output = Self;
45
46 fn sub(self, rhs: Self) -> Self::Output {
47 Self(self.0 - rhs.0)
48 }
49}
50
51pub trait TimeFetcher {
57 fn get_monotonic(&self) -> zx::MonotonicInstant;
59
60 fn get_boot(&self) -> zx::BootInstant;
62}
63
64#[derive(Debug, Default)]
65pub struct DefaultFetcher;
66
67impl TimeFetcher for DefaultFetcher {
68 fn get_monotonic(&self) -> zx::MonotonicInstant {
69 zx::MonotonicInstant::get()
70 }
71
72 fn get_boot(&self) -> zx::BootInstant {
73 zx::BootInstant::get()
74 }
75}
76
77type TimelineEntry = (zx::BootInstant, TimeOffsetMillis);
79
80#[derive(Debug, Default)]
81pub struct TimelineEstimator<T: TimeFetcher> {
82 timeline: VecDeque<TimelineEntry>,
85 max_timeline_size: u64,
87 timeline_overflows: u64,
89 time_fetcher: T,
90}
91
92impl<T: TimeFetcher> TimelineEstimator<T> {
93 pub fn new(time_fetcher: T) -> Self {
94 Self {
95 max_timeline_size: 0,
96 timeline_overflows: 0,
97 timeline: VecDeque::new(),
98 time_fetcher,
99 }
100 }
101
102 pub fn max_timeline_size(&self) -> u64 {
103 self.max_timeline_size
104 }
105
106 pub fn timeline_overflows(&self) -> u64 {
107 self.timeline_overflows
108 }
109
110 pub fn boot_time_to_monotonic_time(
112 &mut self,
113 boot_time: zx::BootInstant,
114 ) -> zx::MonotonicInstant {
115 let timeline = &mut self.timeline;
116 let current_boot_time = self.time_fetcher.get_boot();
117 let mut current_offset = TimeOffsetMillis::from(self.time_fetcher.get_boot())
118 - TimeOffsetMillis::from(self.time_fetcher.get_monotonic());
119 if timeline.is_empty() {
121 timeline.push_back((current_boot_time, current_offset));
122 }
123 let (last_recorded_boot_time, prev_offset) =
124 timeline.back().expect("timeline must have at least one entry after initialization");
125 if current_offset - *prev_offset > TIMELINE_DRIFT_THRESHOLD_MS {
126 let new_boot_time = TimeOffsetMillis::from(self.time_fetcher.get_boot());
131 let prev_boot_time = TimeOffsetMillis::from(current_boot_time);
132 if new_boot_time - prev_boot_time < TIMELINE_BOOT_TIME_THRESHOLD_MS {
133 if !((current_boot_time < boot_time) || boot_time < *last_recorded_boot_time) {
134 if boot_time != current_boot_time {
138 timeline.push_back((boot_time, current_offset));
139 }
140 }
141 timeline.push_back((current_boot_time, current_offset));
142 }
143 if timeline.len() > TIMELINE_MAX_SIZE {
144 while timeline.len() > TIMELINE_TRIM_SIZE {
146 timeline.pop_front();
147 }
148 self.timeline_overflows += 1;
149 }
150 if timeline.len() > self.max_timeline_size as usize {
151 self.max_timeline_size = timeline.len() as u64;
152 }
153 }
154
155 for (boot, offset) in timeline.iter() {
157 if *boot > boot_time {
158 break;
159 }
160 current_offset = *offset;
161 }
162 zx::MonotonicInstant::from_nanos(
164 (TimeOffsetMillis::from(boot_time) - current_offset).to_nanos(),
165 )
166 }
167}
168
169#[cfg(test)]
170mod tests {
171 use std::sync::Arc;
172
173 use super::*;
174
175 #[derive(Clone)]
176 struct FakeFetcher {
177 inner: Arc<std::sync::Mutex<FakeFetcherInner>>,
178 }
179
180 struct FakeFetcherInner {
181 monotonic: zx::MonotonicInstant,
182 boot: zx::BootInstant,
183 }
184
185 impl FakeFetcher {
186 fn new() -> Self {
187 Self {
188 inner: Arc::new(std::sync::Mutex::new(FakeFetcherInner {
189 monotonic: zx::MonotonicInstant::from_nanos(0),
190 boot: zx::BootInstant::from_nanos(0),
191 })),
192 }
193 }
194
195 fn set_times(&self, boot: zx::BootInstant, monotonic: zx::MonotonicInstant) {
196 let mut inner = self.inner.lock().unwrap();
197 inner.boot = boot;
198 inner.monotonic = monotonic;
199 }
200 }
201
202 impl TimeFetcher for FakeFetcher {
203 fn get_monotonic(&self) -> zx::MonotonicInstant {
204 self.inner.lock().unwrap().monotonic
205 }
206
207 fn get_boot(&self) -> zx::BootInstant {
208 self.inner.lock().unwrap().boot
209 }
210 }
211
212 #[test]
213 fn test_boot_time_to_monotonic_time() {
214 let fetcher = FakeFetcher::new();
215 fetcher.set_times(
218 zx::BootInstant::from_nanos(1000 * NANOS_PER_MILLISECOND),
219 zx::MonotonicInstant::from_nanos(100 * NANOS_PER_MILLISECOND),
220 ); let mut state = TimelineEstimator::new(fetcher.clone());
223
224 let mono = state
228 .boot_time_to_monotonic_time(zx::BootInstant::from_nanos(1000 * NANOS_PER_MILLISECOND));
229 assert_eq!(mono.into_nanos(), 100 * NANOS_PER_MILLISECOND);
230
231 fetcher.set_times(
234 zx::BootInstant::from_nanos(1100 * NANOS_PER_MILLISECOND),
235 zx::MonotonicInstant::from_nanos(200 * NANOS_PER_MILLISECOND),
236 );
237
238 let mono = state
240 .boot_time_to_monotonic_time(zx::BootInstant::from_nanos(1100 * NANOS_PER_MILLISECOND));
241 assert_eq!(mono.into_nanos(), 200 * NANOS_PER_MILLISECOND);
242
243 let mono = state
246 .boot_time_to_monotonic_time(zx::BootInstant::from_nanos(1050 * NANOS_PER_MILLISECOND));
247 assert_eq!(mono.into_nanos(), 150 * NANOS_PER_MILLISECOND);
248 }
249
250 #[test]
251 fn test_boot_time_to_monotonic_time_suspend() {
252 let fetcher = FakeFetcher::new();
253
254 fetcher.set_times(
255 zx::BootInstant::from_nanos(1000 * NANOS_PER_MILLISECOND),
256 zx::MonotonicInstant::from_nanos(100 * NANOS_PER_MILLISECOND),
257 );
258
259 let mut state = TimelineEstimator::new(fetcher.clone());
260
261 state
263 .boot_time_to_monotonic_time(zx::BootInstant::from_nanos(1000 * NANOS_PER_MILLISECOND));
264
265 fetcher.set_times(
268 zx::BootInstant::from_nanos(2000 * NANOS_PER_MILLISECOND),
269 zx::MonotonicInstant::from_nanos(100 * NANOS_PER_MILLISECOND),
270 );
271
272 let mono = state
276 .boot_time_to_monotonic_time(zx::BootInstant::from_nanos(2000 * NANOS_PER_MILLISECOND));
277 assert_eq!(mono.into_nanos(), 100 * NANOS_PER_MILLISECOND);
278
279 assert_eq!(state.max_timeline_size, 2);
280
281 let mono = state
284 .boot_time_to_monotonic_time(zx::BootInstant::from_nanos(1500 * NANOS_PER_MILLISECOND));
285 assert_eq!(mono.into_nanos(), 600 * NANOS_PER_MILLISECOND);
286
287 let mono = state
289 .boot_time_to_monotonic_time(zx::BootInstant::from_nanos(2000 * NANOS_PER_MILLISECOND));
290 assert_eq!(mono.into_nanos(), 100 * NANOS_PER_MILLISECOND);
291 }
292
293 #[test]
294 fn test_boot_time_to_monotonic_time_overflow() {
295 let fetcher = FakeFetcher::new();
296 fetcher.set_times(zx::BootInstant::from_nanos(0), zx::MonotonicInstant::from_nanos(0));
297
298 let mut state = TimelineEstimator::new(fetcher.clone());
299 state.boot_time_to_monotonic_time(zx::BootInstant::from_nanos(0));
300
301 let mut current_boot = 0;
304 let current_mono = 0;
305
306 for _ in 0..500 {
307 current_boot += 300 * NANOS_PER_MILLISECOND;
310 fetcher.set_times(
311 zx::BootInstant::from_nanos(current_boot),
312 zx::MonotonicInstant::from_nanos(current_mono),
313 );
314
315 state.boot_time_to_monotonic_time(zx::BootInstant::from_nanos(current_boot));
316 }
317
318 assert!(state.timeline.len() <= TIMELINE_MAX_SIZE);
320 assert!(state.timeline.len() >= TIMELINE_TRIM_SIZE);
321 assert_eq!(state.max_timeline_size, (TIMELINE_MAX_SIZE) as u64);
322
323 assert_eq!(state.timeline.len(), 300);
325
326 for _ in 0..200 {
327 current_boot += 300 * NANOS_PER_MILLISECOND;
328 fetcher.set_times(
329 zx::BootInstant::from_nanos(current_boot),
330 zx::MonotonicInstant::from_nanos(current_mono),
331 );
332 state.boot_time_to_monotonic_time(zx::BootInstant::from_nanos(current_boot));
333 }
334 assert_eq!(state.timeline.len(), 299);
337 }
338
339 #[test]
340 fn test_boot_time_to_monotonic_time_intermediate_update() {
341 let fetcher = FakeFetcher::new();
342 fetcher.set_times(
344 zx::BootInstant::from_nanos(2000 * NANOS_PER_MILLISECOND),
345 zx::MonotonicInstant::from_nanos(1000 * NANOS_PER_MILLISECOND),
346 );
347
348 let mut state = TimelineEstimator::new(fetcher.clone());
349 state
356 .boot_time_to_monotonic_time(zx::BootInstant::from_nanos(2000 * NANOS_PER_MILLISECOND));
357
358 fetcher.set_times(
362 zx::BootInstant::from_nanos(2150 * NANOS_PER_MILLISECOND),
363 zx::MonotonicInstant::from_nanos(600 * NANOS_PER_MILLISECOND),
364 );
365
366 let mono = state
369 .boot_time_to_monotonic_time(zx::BootInstant::from_nanos(2100 * NANOS_PER_MILLISECOND));
370
371 assert_eq!(mono.into_nanos(), 550 * NANOS_PER_MILLISECOND);
373
374 let mono_prev = state
378 .boot_time_to_monotonic_time(zx::BootInstant::from_nanos(2050 * NANOS_PER_MILLISECOND));
379 assert_eq!(mono_prev.into_nanos(), 1050 * NANOS_PER_MILLISECOND);
380
381 let mono_next = state
384 .boot_time_to_monotonic_time(zx::BootInstant::from_nanos(2125 * NANOS_PER_MILLISECOND));
385 assert_eq!(mono_next.into_nanos(), 575 * NANOS_PER_MILLISECOND);
386
387 let mono_curr = state
390 .boot_time_to_monotonic_time(zx::BootInstant::from_nanos(2150 * NANOS_PER_MILLISECOND));
391 assert_eq!(mono_curr.into_nanos(), 600 * NANOS_PER_MILLISECOND);
392
393 assert_eq!(state.max_timeline_size, 3);
395 }
396
397 #[test]
398 fn test_boot_time_to_monotonic_time_retroactive_update() {
399 let fetcher = FakeFetcher::new();
400 fetcher.set_times(
402 zx::BootInstant::from_nanos(1000 * NANOS_PER_MILLISECOND),
403 zx::MonotonicInstant::from_nanos(100 * NANOS_PER_MILLISECOND),
404 );
405
406 let mut state = TimelineEstimator::new(fetcher.clone());
407 state
408 .boot_time_to_monotonic_time(zx::BootInstant::from_nanos(1000 * NANOS_PER_MILLISECOND));
409
410 fetcher.set_times(
413 zx::BootInstant::from_nanos(5000 * NANOS_PER_MILLISECOND),
414 zx::MonotonicInstant::from_nanos(2000 * NANOS_PER_MILLISECOND),
415 );
416
417 let mono = state
423 .boot_time_to_monotonic_time(zx::BootInstant::from_nanos(4500 * NANOS_PER_MILLISECOND));
424 assert_eq!(mono.into_nanos(), 1500 * NANOS_PER_MILLISECOND);
425
426 let mono_next = state
429 .boot_time_to_monotonic_time(zx::BootInstant::from_nanos(4600 * NANOS_PER_MILLISECOND));
430 assert_eq!(mono_next.into_nanos(), 1600 * NANOS_PER_MILLISECOND);
431
432 let mono_prev = state
435 .boot_time_to_monotonic_time(zx::BootInstant::from_nanos(4400 * NANOS_PER_MILLISECOND));
436 assert_eq!(mono_prev.into_nanos(), 3500 * NANOS_PER_MILLISECOND);
437 }
438}