1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
#[cfg(target_arch = "x86")] #[inline(always)] pub fn _rdtsc_arch() -> i64 { unsafe { ::core::arch::x86::_rdtsc() } } #[cfg(target_arch = "x86_64")] #[inline(always)] pub fn _rdtsc_arch() -> i64 { unsafe { ::core::arch::x86_64::_rdtsc() } } #[cfg(not(any(arget_arch = "x86", target_arch = "x86_64")))] compile_error!("Expected x86 or x86_64 architecture."); #[cfg(target_arch = "x86")] pub fn _lfence() { unsafe { ::core::arch::x86::_mm_lfence() } } #[cfg(target_arch = "x86_64")] pub fn _lfence() { unsafe { ::core::arch::x86_64::_mm_lfence() } } #[cfg(not(any(arget_arch = "x86", target_arch = "x86_64")))] compile_error!("Expected x86 or x86_64 architecture."); #[inline(always)] pub fn _rdtsc_precise() -> i64 { _lfence(); _rdtsc_arch() } pub struct MicroBenchState { sum: i64, count: i64, } impl MicroBenchState { #[inline(always)] pub const fn new() -> Self { Self { sum: 0, count: 0 } } } impl Default for MicroBenchState { #[inline(always)] fn default() -> Self { Self::new() } } pub unsafe trait MicroBenchConfig { const PRINT_INTERVAL: i64; const TIMESTAMP_FUNC: fn() -> i64; } #[cfg(feature = "precise_microbench")] pub const DEFAULT_TIMESTAMP_FUNC: fn() -> i64 = _rdtsc_precise; #[cfg(not(feature = "precise_microbench"))] pub const DEFAULT_TIMESTAMP_FUNC: fn() -> i64 = _rdtsc_arch; pub const DEFAULT_PRINT_INTERVAL: i64 = 100000; #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)] pub struct DefaultMicroBenchConfig {} unsafe impl MicroBenchConfig for DefaultMicroBenchConfig { const PRINT_INTERVAL: i64 = DEFAULT_PRINT_INTERVAL; const TIMESTAMP_FUNC: fn() -> i64 = DEFAULT_TIMESTAMP_FUNC; } pub struct MicroBenchImpl<Config: MicroBenchConfig> { state: &'static mut MicroBenchState, msg: &'static str, line: u32, _typeholder: ::core::marker::PhantomData<Config>, start_at: i64, } impl<Config: MicroBenchConfig> MicroBenchImpl<Config> { #[inline(always)] pub fn new(state: &'static mut MicroBenchState, msg: &'static str, line: u32) -> Self { Self { state, msg, line, _typeholder: ::core::marker::PhantomData {}, start_at: Config::TIMESTAMP_FUNC(), } } } impl<Config: MicroBenchConfig> Drop for MicroBenchImpl<Config> { #[inline(always)] fn drop(&mut self) { let diff = Config::TIMESTAMP_FUNC().wrapping_sub(self.start_at); self.state.sum = self.state.sum.wrapping_add(diff); self.state.count = self.state.count.wrapping_add(1); if self.state.count == Config::PRINT_INTERVAL { if self.line != 0 { println!( "Avg cycle: {} at {}:{}", self.state.sum as f64 / Config::PRINT_INTERVAL as f64, self.msg, self.line ); } else { println!( "Avg cycle: {} at {}", self.state.sum as f64 / Config::PRINT_INTERVAL as f64, self.msg ); } *self.state = MicroBenchState { count: 0, sum: 0 }; } } } #[macro_export] macro_rules! DO_MICROBENCH { () => { let __microbench; unsafe { static mut __benchmark_state: $crate::microbench::MicroBenchState = $crate::microbench::MicroBenchState::new(); __microbench = $crate::microbench::MicroBenchImpl::< $crate::microbench::DefaultMicroBenchConfig, >::new(&mut __benchmark_state, file!(), line!()); } }; ($name: expr) => { DO_MICROBENCH!($name, $crate::microbench::DEFAULT_PRINT_INTERVAL); }; ($name: expr, $interval: expr) => { DO_MICROBENCH!($name, $interval, $crate::microbench::DEFAULT_TIMESTAMP_FUNC); }; ($name: expr, $interval: expr, $timestamp: expr) => { let __microbench; unsafe { static mut __benchmark_state: $crate::microbench::MicroBenchState = $crate::microbench::MicroBenchState::new(); struct __temp_config {} unsafe impl $crate::microbench::MicroBenchConfig for __temp_config { const PRINT_INTERVAL: i64 = $interval; const TIMESTAMP_FUNC: fn() -> i64 = $timestamp; } __microbench = $crate::microbench::MicroBenchImpl::<__temp_config>::new( &mut __benchmark_state, $name, 0, ); } }; } #[macro_export] macro_rules! DO_MICROBENCH_WITH_NAME { ($name: expr) => { DO_MICROBENCH!($name); }; } #[macro_export] macro_rules! DO_MICROBENCH_WITH_NAME_INTERVAL { ($name: expr, $interval: expr) => { DO_MICROBENCH!($name, $interval); }; }