sol_trade_sdk/common/
clock.rs1use std::time::Instant;
7
8#[derive(Debug)]
10pub struct HighPerformanceClock {
11 base_instant: Instant,
12 base_timestamp_us: i64,
13 last_calibration: Instant,
14 calibration_interval_secs: u64,
15}
16
17impl HighPerformanceClock {
18 pub fn new() -> Self {
20 Self::new_with_calibration_interval(300)
21 }
22
23 pub fn new_with_calibration_interval(calibration_interval_secs: u64) -> Self {
25 let mut best_offset = i64::MAX;
26 let mut best_instant = Instant::now();
27 let mut best_timestamp = chrono::Utc::now().timestamp_micros();
28
29 for _ in 0..3 {
30 let instant_before = Instant::now();
31 let timestamp = chrono::Utc::now().timestamp_micros();
32 let instant_after = Instant::now();
33 let sample_latency = instant_after.duration_since(instant_before).as_nanos() as i64;
34 if sample_latency < best_offset {
35 best_offset = sample_latency;
36 best_instant = instant_before;
37 best_timestamp = timestamp;
38 }
39 }
40
41 Self {
42 base_instant: best_instant,
43 base_timestamp_us: best_timestamp,
44 last_calibration: best_instant,
45 calibration_interval_secs,
46 }
47 }
48
49 #[inline(always)]
50 pub fn now_micros(&self) -> i64 {
51 let elapsed = self.base_instant.elapsed();
52 self.base_timestamp_us + elapsed.as_micros() as i64
53 }
54
55 pub fn now_micros_with_calibration(&mut self) -> i64 {
57 if self.last_calibration.elapsed().as_secs() >= self.calibration_interval_secs {
58 self.recalibrate();
59 }
60 self.now_micros()
61 }
62
63 fn recalibrate(&mut self) {
64 let current_monotonic = Instant::now();
65 let current_utc = chrono::Utc::now().timestamp_micros();
66 let expected_utc = self.base_timestamp_us
67 + current_monotonic.duration_since(self.base_instant).as_micros() as i64;
68 let drift_us = current_utc - expected_utc;
69 if drift_us.abs() > 1000 {
70 self.base_instant = current_monotonic;
71 self.base_timestamp_us = current_utc;
72 }
73 self.last_calibration = current_monotonic;
74 }
75}
76
77impl Default for HighPerformanceClock {
78 fn default() -> Self {
79 Self::new()
80 }
81}
82
83static HIGH_PERF_CLOCK: once_cell::sync::OnceCell<HighPerformanceClock> =
84 once_cell::sync::OnceCell::new();
85
86#[inline(always)]
88pub fn now_micros() -> i64 {
89 let clock = HIGH_PERF_CLOCK.get_or_init(HighPerformanceClock::new);
90 clock.now_micros()
91}
92
93#[inline(always)]
95pub fn elapsed_micros_since(start_timestamp_us: i64) -> i64 {
96 now_micros() - start_timestamp_us
97}