Skip to main content

sol_trade_sdk/common/
fast_timing.rs

1//! 🚀 快速计时模块 - 减少 Instant::now() 系统调用开销
2//!
3//! 使用 syscall_bypass 提供的快速时间戳避免频繁的系统调用
4
5use crate::perf::syscall_bypass::SystemCallBypassManager;
6use once_cell::sync::Lazy;
7use std::time::{Duration, Instant};
8
9/// 全局快速时间提供器
10static FAST_TIMER: Lazy<FastTimer> = Lazy::new(|| FastTimer::new());
11
12/// 快速计时器 - 减少系统调用开销
13pub struct FastTimer {
14    bypass_manager: SystemCallBypassManager,
15    _base_instant: Instant,
16    _base_nanos: u64,
17}
18
19impl FastTimer {
20    fn new() -> Self {
21        use crate::perf::syscall_bypass::SyscallBypassConfig;
22
23        let bypass_manager = SystemCallBypassManager::new(SyscallBypassConfig::default())
24            .expect("Failed to create SystemCallBypassManager");
25
26        let base_instant = Instant::now();
27        let base_nanos = bypass_manager.fast_timestamp_nanos();
28
29        Self { bypass_manager, _base_instant: base_instant, _base_nanos: base_nanos }
30    }
31
32    /// 🚀 获取当前时间戳(纳秒) - 使用快速系统调用绕过
33    #[inline(always)]
34    pub fn now_nanos(&self) -> u64 {
35        self.bypass_manager.fast_timestamp_nanos()
36    }
37
38    /// 🚀 获取当前时间戳(微秒)
39    #[inline(always)]
40    pub fn now_micros(&self) -> u64 {
41        self.now_nanos() / 1_000
42    }
43
44    /// 🚀 获取当前时间戳(毫秒)
45    #[inline(always)]
46    pub fn now_millis(&self) -> u64 {
47        self.now_nanos() / 1_000_000
48    }
49
50    /// 🚀 计算从开始到现在的耗时(纳秒)
51    #[inline(always)]
52    pub fn elapsed_nanos(&self, start_nanos: u64) -> u64 {
53        self.now_nanos().saturating_sub(start_nanos)
54    }
55
56    /// 🚀 计算从开始到现在的耗时(Duration)
57    #[inline(always)]
58    pub fn elapsed_duration(&self, start_nanos: u64) -> Duration {
59        Duration::from_nanos(self.elapsed_nanos(start_nanos))
60    }
61}
62
63/// 🚀 快速获取当前时间戳(纳秒)- 全局函数
64///
65/// 使用 syscall_bypass 避免频繁的 clock_gettime 系统调用
66#[inline(always)]
67pub fn fast_now_nanos() -> u64 {
68    FAST_TIMER.now_nanos()
69}
70
71/// 🚀 快速获取当前时间戳(微秒)
72#[inline(always)]
73pub fn fast_now_micros() -> u64 {
74    FAST_TIMER.now_micros()
75}
76
77/// 🚀 快速获取当前时间戳(毫秒)
78#[inline(always)]
79pub fn fast_now_millis() -> u64 {
80    FAST_TIMER.now_millis()
81}
82
83/// 🚀 计算耗时(纳秒)
84#[inline(always)]
85pub fn fast_elapsed_nanos(start_nanos: u64) -> u64 {
86    FAST_TIMER.elapsed_nanos(start_nanos)
87}
88
89/// 🚀 计算耗时(Duration)
90#[inline(always)]
91pub fn fast_elapsed(start_nanos: u64) -> Duration {
92    FAST_TIMER.elapsed_duration(start_nanos)
93}
94
95/// 快速计时器句柄 - 用于测量代码块耗时
96pub struct FastStopwatch {
97    start_nanos: u64,
98    #[allow(dead_code)]
99    label: &'static str,
100}
101
102impl FastStopwatch {
103    /// 创建并启动计时器
104    #[inline(always)]
105    pub fn start(label: &'static str) -> Self {
106        Self { start_nanos: fast_now_nanos(), label }
107    }
108
109    /// 获取已耗时(纳秒)
110    #[inline(always)]
111    pub fn elapsed_nanos(&self) -> u64 {
112        fast_elapsed_nanos(self.start_nanos)
113    }
114
115    /// 获取已耗时(Duration)
116    #[inline(always)]
117    pub fn elapsed(&self) -> Duration {
118        fast_elapsed(self.start_nanos)
119    }
120
121    /// 获取已耗时(微秒)
122    #[inline(always)]
123    pub fn elapsed_micros(&self) -> u64 {
124        self.elapsed_nanos() / 1_000
125    }
126
127    /// 获取已耗时(毫秒)
128    #[inline(always)]
129    pub fn elapsed_millis(&self) -> u64 {
130        self.elapsed_nanos() / 1_000_000
131    }
132}
133
134#[cfg(test)]
135mod tests {
136    use super::*;
137
138    #[test]
139    fn test_fast_timing() {
140        let start = fast_now_nanos();
141        std::thread::sleep(Duration::from_millis(10));
142        let elapsed = fast_elapsed_nanos(start);
143
144        // Scheduler jitter can exceed the sleep duration; the fast timer must not under-report.
145        assert!(elapsed >= 9_000_000);
146    }
147
148    #[test]
149    fn test_stopwatch() {
150        let sw = FastStopwatch::start("test");
151        std::thread::sleep(Duration::from_millis(10));
152        let elapsed_ms = sw.elapsed_millis();
153
154        assert!(elapsed_ms >= 9);
155    }
156
157    #[test]
158    fn test_fast_now_overhead() {
159        // This is a coarse regression guard, not a benchmark. On non-Linux targets
160        // the fast timer uses `Instant::elapsed()`, and CI/desktop scheduler jitter can
161        // move a single run above 100ns even when the code path is still sub-microsecond.
162        let iterations = 100_000;
163        for _ in 0..1_000 {
164            let _ = fast_now_nanos();
165        }
166        let start = Instant::now();
167
168        for _ in 0..iterations {
169            let _ = fast_now_nanos();
170        }
171
172        let total_elapsed = start.elapsed();
173        let avg_per_call = total_elapsed.as_nanos() / iterations;
174
175        if crate::common::sdk_log::sdk_log_enabled() {
176            println!("Average fast_now_nanos() call: {}ns", avg_per_call);
177        }
178
179        // Keep the hot-path timer safely sub-microsecond without making the test flaky.
180        assert!(avg_per_call < 500);
181    }
182
183    #[test]
184    fn test_instant_now_overhead() {
185        // 对比标准 Instant::now() 的开销
186        let iterations = 10_000;
187        let start = Instant::now();
188
189        for _ in 0..iterations {
190            let _ = Instant::now();
191        }
192
193        let total_elapsed = start.elapsed();
194        let avg_per_call = total_elapsed.as_nanos() / iterations;
195
196        if crate::common::sdk_log::sdk_log_enabled() {
197            println!("Average Instant::now() call: {}ns", avg_per_call);
198        }
199    }
200}