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.duration_since(self.base_instant).as_micros() as i64;
128
129 let drift_us = current_utc - expected_utc;
131
132 if drift_us.abs() > 1000 {
134 self.base_instant = current_monotonic;
135 self.base_timestamp_us = current_utc;
136 }
137
138 self.last_calibration = current_monotonic;
139 }
140
141 #[inline(always)]
149 pub fn elapsed_micros_since(&self, start_timestamp_us: i64) -> i64 {
150 self.now_micros() - start_timestamp_us
151 }
152
153 #[inline(always)]
155 pub fn now_nanos(&self) -> i128 {
156 let elapsed = self.base_instant.elapsed();
157 (self.base_timestamp_us as i128 * 1000) + elapsed.as_nanos() as i128
158 }
159
160 pub fn reset(&mut self) {
162 *self = Self::new_with_calibration_interval(self.calibration_interval_secs);
163 }
164}
165
166impl Default for HighPerformanceClock {
167 fn default() -> Self {
168 Self::new()
169 }
170}
171
172static HIGH_PERF_CLOCK: once_cell::sync::OnceCell<HighPerformanceClock> =
174 once_cell::sync::OnceCell::new();
175
176#[inline(always)]
192pub fn now_micros() -> i64 {
193 let clock = HIGH_PERF_CLOCK.get_or_init(HighPerformanceClock::new);
194 clock.now_micros()
195}
196
197#[inline(always)]
215pub fn elapsed_micros_since(start_timestamp_us: i64) -> i64 {
216 now_micros() - start_timestamp_us
217}
218
219#[inline(always)]
223pub fn now_nanos() -> i128 {
224 let clock = HIGH_PERF_CLOCK.get_or_init(HighPerformanceClock::new);
225 clock.now_nanos()
226}
227
228#[inline(always)]
230pub fn now_us() -> i64 {
231 #[cfg(target_os = "windows")]
232 {
233 now_micros()
234 }
235
236 #[cfg(not(target_os = "windows"))]
237 {
238 let clock_id = {
239 #[cfg(target_os = "linux")]
240 {
241 libc::CLOCK_REALTIME_COARSE
242 }
243
244 #[cfg(not(target_os = "linux"))]
245 {
246 libc::CLOCK_REALTIME
247 }
248 };
249
250 let mut ts = libc::timespec { tv_sec: 0, tv_nsec: 0 };
251 unsafe {
252 libc::clock_gettime(clock_id, &mut ts);
253 }
254 (ts.tv_sec as i64) * 1_000_000 + (ts.tv_nsec as i64) / 1_000
255 }
256}
257
258#[cfg(test)]
259mod tests {
260 use super::*;
261 use std::thread;
262 use std::time::Duration;
263
264 #[test]
265 fn test_high_performance_clock_basic() {
266 let clock = HighPerformanceClock::new();
267 let t1 = clock.now_micros();
268 thread::sleep(Duration::from_millis(10));
269 let t2 = clock.now_micros();
270
271 let elapsed = t2 - t1;
272 assert!(elapsed >= 10_000, "elapsed: {} μs", elapsed); assert!(elapsed < 20_000, "elapsed: {} μs", elapsed); }
275
276 #[test]
277 fn test_elapsed_micros_since() {
278 let clock = HighPerformanceClock::new();
279 let start = clock.now_micros();
280 thread::sleep(Duration::from_millis(5));
281 let elapsed = clock.elapsed_micros_since(start);
282
283 assert!(elapsed >= 5_000, "elapsed: {} μs", elapsed);
284 assert!(elapsed < 10_000, "elapsed: {} μs", elapsed);
285 }
286
287 #[test]
288 fn test_global_clock() {
289 let t1 = now_micros();
290 thread::sleep(Duration::from_millis(1));
291 let t2 = now_micros();
292
293 assert!(t2 > t1);
294 assert!(t2 - t1 >= 1_000); }
296
297 #[test]
298 fn test_elapsed_global() {
299 let start = now_micros();
300 thread::sleep(Duration::from_millis(2));
301 let elapsed = elapsed_micros_since(start);
302
303 assert!(elapsed >= 2_000, "elapsed: {} μs", elapsed);
304 assert!(elapsed < 5_000, "elapsed: {} μs", elapsed);
305 }
306
307 #[test]
308 fn test_clock_precision() {
309 let clock = HighPerformanceClock::new();
310 let mut timestamps = Vec::new();
311
312 for _ in 0..100 {
314 timestamps.push(clock.now_micros());
315 }
316
317 for i in 1..timestamps.len() {
319 assert!(timestamps[i] >= timestamps[i - 1], "时间戳应该单调递增");
320 }
321 }
322
323 #[test]
324 fn test_calibration() {
325 let mut clock = HighPerformanceClock::new_with_calibration_interval(0); let t1 = clock.now_micros_with_calibration();
327 thread::sleep(Duration::from_millis(10));
328 let t2 = clock.now_micros_with_calibration();
329
330 let elapsed = t2 - t1;
331 assert!(elapsed >= 10_000, "elapsed: {} μs", elapsed);
332 }
333}