sol_parser_sdk/core/
clock.rs1use std::time::Instant;
32
33#[derive(Debug)]
37pub struct HighPerformanceClock {
38 base_instant: Instant,
40 base_timestamp_us: i64,
42 last_calibration: Instant,
44 calibration_interval_secs: u64,
46}
47
48impl HighPerformanceClock {
49 pub fn new() -> Self {
51 Self::new_with_calibration_interval(300)
52 }
53
54 pub fn new_with_calibration_interval(calibration_interval_secs: u64) -> Self {
62 let mut best_offset = i64::MAX;
64 let mut best_instant = Instant::now();
65 let mut best_timestamp = chrono::Utc::now().timestamp_micros();
66
67 for _ in 0..3 {
69 let instant_before = Instant::now();
70 let timestamp = chrono::Utc::now().timestamp_micros();
71 let instant_after = Instant::now();
72
73 let sample_latency = instant_after.duration_since(instant_before).as_nanos() as i64;
74
75 if sample_latency < best_offset {
76 best_offset = sample_latency;
77 best_instant = instant_before;
78 best_timestamp = timestamp;
79 }
80 }
81
82 Self {
83 base_instant: best_instant,
84 base_timestamp_us: best_timestamp,
85 last_calibration: best_instant,
86 calibration_interval_secs,
87 }
88 }
89
90 #[inline(always)]
98 pub fn now_micros(&self) -> i64 {
99 let elapsed = self.base_instant.elapsed();
100 self.base_timestamp_us + elapsed.as_micros() as i64
101 }
102
103 pub fn now_micros_with_calibration(&mut self) -> i64 {
108 if self.last_calibration.elapsed().as_secs() >= self.calibration_interval_secs {
110 self.recalibrate();
111 }
112 self.now_micros()
113 }
114
115 fn recalibrate(&mut self) {
122 let current_monotonic = Instant::now();
123 let current_utc = chrono::Utc::now().timestamp_micros();
124
125 let expected_utc = self.base_timestamp_us
127 + current_monotonic
128 .duration_since(self.base_instant)
129 .as_micros() as i64;
130
131 let drift_us = current_utc - expected_utc;
133
134 if drift_us.abs() > 1000 {
136 self.base_instant = current_monotonic;
137 self.base_timestamp_us = current_utc;
138 }
139
140 self.last_calibration = current_monotonic;
141 }
142
143 #[inline(always)]
151 pub fn elapsed_micros_since(&self, start_timestamp_us: i64) -> i64 {
152 self.now_micros() - start_timestamp_us
153 }
154
155 #[inline(always)]
157 pub fn now_nanos(&self) -> i128 {
158 let elapsed = self.base_instant.elapsed();
159 (self.base_timestamp_us as i128 * 1000) + elapsed.as_nanos() as i128
160 }
161
162 pub fn reset(&mut self) {
164 *self = Self::new_with_calibration_interval(self.calibration_interval_secs);
165 }
166}
167
168impl Default for HighPerformanceClock {
169 fn default() -> Self {
170 Self::new()
171 }
172}
173
174static HIGH_PERF_CLOCK: once_cell::sync::OnceCell<HighPerformanceClock> =
176 once_cell::sync::OnceCell::new();
177
178#[inline(always)]
194pub fn now_micros() -> i64 {
195 let clock = HIGH_PERF_CLOCK.get_or_init(HighPerformanceClock::new);
196 clock.now_micros()
197}
198
199#[inline(always)]
217pub fn elapsed_micros_since(start_timestamp_us: i64) -> i64 {
218 now_micros() - start_timestamp_us
219}
220
221#[inline(always)]
225pub fn now_nanos() -> i128 {
226 let clock = HIGH_PERF_CLOCK.get_or_init(HighPerformanceClock::new);
227 clock.now_nanos()
228}
229
230#[inline(always)]
232pub fn now_us() -> i64 {
233 #[cfg(target_os = "windows")]
234 {
235 now_micros()
236 }
237
238 #[cfg(not(target_os = "windows"))]
239 {
240 let clock_id = {
241 #[cfg(target_os = "linux")]
242 { libc::CLOCK_REALTIME_COARSE }
243
244 #[cfg(not(target_os = "linux"))]
245 { libc::CLOCK_REALTIME }
246 };
247
248 let mut ts = libc::timespec { tv_sec: 0, tv_nsec: 0 };
249 unsafe {
250 libc::clock_gettime(clock_id, &mut ts);
251 }
252 (ts.tv_sec as i64) * 1_000_000 + (ts.tv_nsec as i64) / 1_000
253 }
254}
255
256#[cfg(test)]
257mod tests {
258 use super::*;
259 use std::thread;
260 use std::time::Duration;
261
262 #[test]
263 fn test_high_performance_clock_basic() {
264 let clock = HighPerformanceClock::new();
265 let t1 = clock.now_micros();
266 thread::sleep(Duration::from_millis(10));
267 let t2 = clock.now_micros();
268
269 let elapsed = t2 - t1;
270 assert!(elapsed >= 10_000, "elapsed: {} μs", elapsed); assert!(elapsed < 20_000, "elapsed: {} μs", elapsed); }
273
274 #[test]
275 fn test_elapsed_micros_since() {
276 let clock = HighPerformanceClock::new();
277 let start = clock.now_micros();
278 thread::sleep(Duration::from_millis(5));
279 let elapsed = clock.elapsed_micros_since(start);
280
281 assert!(elapsed >= 5_000, "elapsed: {} μs", elapsed);
282 assert!(elapsed < 10_000, "elapsed: {} μs", elapsed);
283 }
284
285 #[test]
286 fn test_global_clock() {
287 let t1 = now_micros();
288 thread::sleep(Duration::from_millis(1));
289 let t2 = now_micros();
290
291 assert!(t2 > t1);
292 assert!(t2 - t1 >= 1_000); }
294
295 #[test]
296 fn test_elapsed_global() {
297 let start = now_micros();
298 thread::sleep(Duration::from_millis(2));
299 let elapsed = elapsed_micros_since(start);
300
301 assert!(elapsed >= 2_000, "elapsed: {} μs", elapsed);
302 assert!(elapsed < 5_000, "elapsed: {} μs", elapsed);
303 }
304
305 #[test]
306 fn test_clock_precision() {
307 let clock = HighPerformanceClock::new();
308 let mut timestamps = Vec::new();
309
310 for _ in 0..100 {
312 timestamps.push(clock.now_micros());
313 }
314
315 for i in 1..timestamps.len() {
317 assert!(
318 timestamps[i] >= timestamps[i - 1],
319 "时间戳应该单调递增"
320 );
321 }
322 }
323
324 #[test]
325 fn test_calibration() {
326 let mut clock = HighPerformanceClock::new_with_calibration_interval(0); let t1 = clock.now_micros_with_calibration();
328 thread::sleep(Duration::from_millis(10));
329 let t2 = clock.now_micros_with_calibration();
330
331 let elapsed = t2 - t1;
332 assert!(elapsed >= 10_000, "elapsed: {} μs", elapsed);
333 }
334}