metrics_lib/
timer.rs

1//! # High-Precision Timer
2//!
3//! Ultra-fast timer implementation with nanosecond precision.
4//!
5//! ## Features
6//!
7//! - **Nanosecond precision** - Using system high-resolution clocks
8//! - **Zero allocation** - Pure stack operations
9//! - **RAII support** - Automatic timing with scoped timers
10//! - **Lock-free** - Never blocks, never waits
11//! - **Cache optimized** - Aligned to prevent false sharing
12
13use crate::{MetricsError, Result};
14use std::sync::atomic::{AtomicU64, Ordering};
15use std::time::{Duration, Instant};
16
17/// High-precision timer with automatic statistics
18///
19/// Optimized for sub-10ns timing operations.
20/// Cache-line aligned to prevent false sharing.
21#[repr(align(64))]
22pub struct Timer {
23    /// Number of timing samples
24    count: AtomicU64,
25    /// Sum of all recorded durations in nanoseconds
26    total_nanos: AtomicU64,
27    /// Minimum duration in nanoseconds
28    min_nanos: AtomicU64,
29    /// Maximum duration in nanoseconds
30    max_nanos: AtomicU64,
31    /// Creation timestamp
32    created_at: Instant,
33}
34
35/// Running timer instance (RAII)
36///
37/// When dropped, automatically records the elapsed time
38pub struct RunningTimer<'a> {
39    timer: &'a Timer,
40    start_time: Instant,
41    stopped: bool,
42}
43
44/// Timer statistics
45#[derive(Debug, Clone)]
46pub struct TimerStats {
47    /// Total number of timing samples
48    pub count: u64,
49    /// Sum of all durations
50    pub total: Duration,
51    /// Average duration
52    pub average: Duration,
53    /// Minimum duration recorded
54    pub min: Duration,
55    /// Maximum duration recorded
56    pub max: Duration,
57    /// Time since timer creation
58    pub age: Duration,
59    /// Rate of samples per second
60    pub rate_per_second: f64,
61}
62
63impl Timer {
64    /// Create new timer
65    #[inline]
66    pub fn new() -> Self {
67        Self {
68            count: AtomicU64::new(0),
69            total_nanos: AtomicU64::new(0),
70            min_nanos: AtomicU64::new(u64::MAX),
71            max_nanos: AtomicU64::new(0),
72            created_at: Instant::now(),
73        }
74    }
75
76    /// Try to record nanoseconds directly with overflow checks
77    ///
78    /// Returns `Err(MetricsError::Overflow)` if adding `duration_ns` would
79    /// overflow internal counters (`total_nanos` or `count`). On success
80    /// updates min/max as needed.
81    ///
82    /// Example
83    /// ```
84    /// use metrics_lib::{Timer, MetricsError};
85    /// let t = Timer::new();
86    /// t.try_record_ns(1_000).unwrap();
87    /// assert_eq!(t.count(), 1);
88    /// assert!(matches!(t.try_record_ns(u64::MAX), Err(MetricsError::Overflow)));
89    /// ```
90    #[inline(always)]
91    pub fn try_record_ns(&self, duration_ns: u64) -> Result<()> {
92        // Check total_nanos overflow
93        let total = self.total_nanos.load(Ordering::Relaxed);
94        if total.checked_add(duration_ns).is_none() {
95            return Err(MetricsError::Overflow);
96        }
97
98        // Check count overflow
99        let cnt = self.count.load(Ordering::Relaxed);
100        if cnt == u64::MAX {
101            return Err(MetricsError::Overflow);
102        }
103
104        // Apply updates
105        self.total_nanos.fetch_add(duration_ns, Ordering::Relaxed);
106        self.count.fetch_add(1, Ordering::Relaxed);
107
108        // Update min and max
109        self.update_min(duration_ns);
110        self.update_max(duration_ns);
111        Ok(())
112    }
113
114    /// Start timing - returns RAII guard that auto-records on drop
115    #[inline(always)]
116    pub fn start(&self) -> RunningTimer<'_> {
117        RunningTimer {
118            timer: self,
119            start_time: Instant::now(),
120            stopped: false,
121        }
122    }
123
124    /// Record a duration manually
125    #[inline]
126    pub fn record(&self, duration: Duration) {
127        let duration_ns = duration.as_nanos() as u64;
128        self.record_ns(duration_ns);
129    }
130
131    /// Try to record a duration with overflow checks
132    ///
133    /// Returns `Err(MetricsError::Overflow)` if adding this sample would overflow
134    /// internal counters.
135    ///
136    /// Example
137    /// ```
138    /// use metrics_lib::{Timer, MetricsError};
139    /// use std::time::Duration;
140    /// let t = Timer::new();
141    /// assert!(t.try_record(Duration::from_millis(1)).is_ok());
142    /// ```
143    #[inline]
144    pub fn try_record(&self, duration: Duration) -> Result<()> {
145        let duration_ns = duration.as_nanos() as u64;
146        self.try_record_ns(duration_ns)
147    }
148
149    /// Record nanoseconds directly - fastest path
150    #[inline(always)]
151    pub fn record_ns(&self, duration_ns: u64) {
152        // Update total and count
153        self.total_nanos.fetch_add(duration_ns, Ordering::Relaxed);
154        self.count.fetch_add(1, Ordering::Relaxed);
155
156        // Update min (compare-and-swap loop)
157        self.update_min(duration_ns);
158
159        // Update max (compare-and-swap loop)
160        self.update_max(duration_ns);
161    }
162
163    /// Record multiple durations at once
164    #[inline]
165    pub fn record_batch(&self, durations: &[Duration]) {
166        if durations.is_empty() {
167            return;
168        }
169
170        let mut total_ns = 0u64;
171        let mut local_min = u64::MAX;
172        let mut local_max = 0u64;
173
174        for duration in durations {
175            let ns = duration.as_nanos() as u64;
176            total_ns += ns;
177            local_min = local_min.min(ns);
178            local_max = local_max.max(ns);
179        }
180
181        self.total_nanos.fetch_add(total_ns, Ordering::Relaxed);
182        self.count
183            .fetch_add(durations.len() as u64, Ordering::Relaxed);
184
185        if local_min < u64::MAX {
186            self.update_min(local_min);
187        }
188        if local_max > 0 {
189            self.update_max(local_max);
190        }
191    }
192
193    /// Try to record multiple durations at once with overflow checks
194    ///
195    /// Returns `Err(MetricsError::Overflow)` if the aggregated additions would
196    /// overflow internal counters. Updates min/max based on batch extrema.
197    ///
198    /// Example
199    /// ```
200    /// use metrics_lib::Timer;
201    /// use std::time::Duration;
202    /// let t = Timer::new();
203    /// t.try_record_batch(&[Duration::from_micros(5), Duration::from_micros(10)]).unwrap();
204    /// assert_eq!(t.count(), 2);
205    /// ```
206    #[inline]
207    pub fn try_record_batch(&self, durations: &[Duration]) -> Result<()> {
208        if durations.is_empty() {
209            return Ok(());
210        }
211
212        let mut total_ns: u64 = 0;
213        let mut local_min = u64::MAX;
214        let mut local_max = 0u64;
215
216        for d in durations {
217            let ns = d.as_nanos() as u64;
218            total_ns = total_ns.checked_add(ns).ok_or(MetricsError::Overflow)?;
219            local_min = local_min.min(ns);
220            local_max = local_max.max(ns);
221        }
222
223        // Check counters will not overflow
224        let current_total = self.total_nanos.load(Ordering::Relaxed);
225        if current_total.checked_add(total_ns).is_none() {
226            return Err(MetricsError::Overflow);
227        }
228        let current_count = self.count.load(Ordering::Relaxed);
229        let add_count = durations.len() as u64;
230        if current_count.checked_add(add_count).is_none() {
231            return Err(MetricsError::Overflow);
232        }
233
234        // Apply updates
235        self.total_nanos.fetch_add(total_ns, Ordering::Relaxed);
236        self.count.fetch_add(add_count, Ordering::Relaxed);
237        if local_min < u64::MAX {
238            self.update_min(local_min);
239        }
240        if local_max > 0 {
241            self.update_max(local_max);
242        }
243        Ok(())
244    }
245
246    /// Get current count of samples
247    #[inline(always)]
248    pub fn count(&self) -> u64 {
249        self.count.load(Ordering::Relaxed)
250    }
251
252    /// Get total accumulated time
253    #[inline]
254    pub fn total(&self) -> Duration {
255        Duration::from_nanos(self.total_nanos.load(Ordering::Relaxed))
256    }
257
258    /// Get average duration
259    #[inline]
260    pub fn average(&self) -> Duration {
261        let count = self.count();
262        if count == 0 {
263            return Duration::ZERO;
264        }
265
266        let total_ns = self.total_nanos.load(Ordering::Relaxed);
267        Duration::from_nanos(total_ns / count)
268    }
269
270    /// Get minimum duration
271    #[inline]
272    pub fn min(&self) -> Duration {
273        let min_ns = self.min_nanos.load(Ordering::Relaxed);
274        if min_ns == u64::MAX {
275            Duration::ZERO
276        } else {
277            Duration::from_nanos(min_ns)
278        }
279    }
280
281    /// Get maximum duration
282    #[inline]
283    pub fn max(&self) -> Duration {
284        Duration::from_nanos(self.max_nanos.load(Ordering::Relaxed))
285    }
286
287    /// Reset all statistics
288    #[inline]
289    pub fn reset(&self) {
290        self.total_nanos.store(0, Ordering::SeqCst);
291        self.count.store(0, Ordering::SeqCst);
292        self.min_nanos.store(u64::MAX, Ordering::SeqCst);
293        self.max_nanos.store(0, Ordering::SeqCst);
294    }
295
296    /// Get comprehensive statistics
297    pub fn stats(&self) -> TimerStats {
298        let count = self.count();
299        let total_ns = self.total_nanos.load(Ordering::Relaxed);
300        let min_ns = self.min_nanos.load(Ordering::Relaxed);
301        let max_ns = self.max_nanos.load(Ordering::Relaxed);
302
303        let total = Duration::from_nanos(total_ns);
304        let average = if count > 0 {
305            Duration::from_nanos(total_ns / count)
306        } else {
307            Duration::ZERO
308        };
309
310        let min = if min_ns == u64::MAX {
311            Duration::ZERO
312        } else {
313            Duration::from_nanos(min_ns)
314        };
315
316        let max = Duration::from_nanos(max_ns);
317        let age = self.created_at.elapsed();
318
319        let rate_per_second = if age.as_secs_f64() > 0.0 {
320            count as f64 / age.as_secs_f64()
321        } else {
322            0.0
323        };
324
325        TimerStats {
326            count,
327            total,
328            average,
329            min,
330            max,
331            age,
332            rate_per_second,
333        }
334    }
335
336    /// Get age since creation
337    #[inline]
338    pub fn age(&self) -> Duration {
339        self.created_at.elapsed()
340    }
341
342    /// Check if timer has recorded any samples
343    #[inline]
344    pub fn is_empty(&self) -> bool {
345        self.count() == 0
346    }
347
348    /// Get samples per second rate
349    #[inline]
350    pub fn rate_per_second(&self) -> f64 {
351        let age_seconds = self.age().as_secs_f64();
352        if age_seconds > 0.0 {
353            self.count() as f64 / age_seconds
354        } else {
355            0.0
356        }
357    }
358
359    // Internal helper methods
360
361    #[inline(always)]
362    fn update_min(&self, value: u64) {
363        loop {
364            let current = self.min_nanos.load(Ordering::Relaxed);
365            if value >= current {
366                break; // Current min is already smaller
367            }
368
369            match self.min_nanos.compare_exchange_weak(
370                current,
371                value,
372                Ordering::Relaxed,
373                Ordering::Relaxed,
374            ) {
375                Ok(_) => break,
376                Err(_) => continue, // Retry
377            }
378        }
379    }
380
381    #[inline(always)]
382    fn update_max(&self, value: u64) {
383        loop {
384            let current = self.max_nanos.load(Ordering::Relaxed);
385            if value <= current {
386                break; // Current max is already larger
387            }
388
389            match self.max_nanos.compare_exchange_weak(
390                current,
391                value,
392                Ordering::Relaxed,
393                Ordering::Relaxed,
394            ) {
395                Ok(_) => break,
396                Err(_) => continue, // Retry
397            }
398        }
399    }
400}
401
402impl Default for Timer {
403    #[inline]
404    fn default() -> Self {
405        Self::new()
406    }
407}
408
409impl std::fmt::Display for Timer {
410    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
411        let stats = self.stats();
412        write!(f, "Timer(count: {}, avg: {:?})", stats.count, stats.average)
413    }
414}
415
416impl std::fmt::Debug for Timer {
417    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
418        let stats = self.stats();
419        f.debug_struct("Timer")
420            .field("count", &stats.count)
421            .field("total", &stats.total)
422            .field("average", &stats.average)
423            .field("min", &stats.min)
424            .field("max", &stats.max)
425            .field("rate_per_second", &stats.rate_per_second)
426            .finish()
427    }
428}
429
430// Thread safety
431unsafe impl Send for Timer {}
432unsafe impl Sync for Timer {}
433
434/// Running timer implementation (RAII)
435impl<'a> RunningTimer<'a> {
436    /// Get elapsed time without stopping the timer
437    #[inline]
438    pub fn elapsed(&self) -> Duration {
439        self.start_time.elapsed()
440    }
441
442    /// Stop the timer manually and record the duration
443    #[inline]
444    pub fn stop(mut self) {
445        if !self.stopped {
446            let elapsed = self.start_time.elapsed();
447            self.timer.record(elapsed);
448            self.stopped = true;
449        }
450        // Timer is consumed here, preventing double recording
451    }
452}
453
454impl<'a> Drop for RunningTimer<'a> {
455    #[inline]
456    fn drop(&mut self) {
457        if !self.stopped {
458            let elapsed = self.start_time.elapsed();
459            self.timer.record(elapsed);
460        }
461    }
462}
463
464/// Utility functions for timing
465pub mod utils {
466    use super::*;
467
468    /// Time a function execution and return the result + duration
469    #[inline]
470    pub fn time_fn<T>(f: impl FnOnce() -> T) -> (T, Duration) {
471        let start = Instant::now();
472        let result = f();
473        let duration = start.elapsed();
474        (result, duration)
475    }
476
477    /// Time a function and record the duration in the provided timer
478    #[inline]
479    pub fn time_and_record<T>(timer: &Timer, f: impl FnOnce() -> T) -> T {
480        let _timing_guard = timer.start();
481        f() // Timer automatically records when guard drops
482    }
483
484    /// Create a scoped timer that records to the provided timer
485    #[inline]
486    pub fn scoped_timer(timer: &Timer) -> RunningTimer<'_> {
487        timer.start()
488    }
489
490    /// Benchmark a function with multiple iterations
491    pub fn benchmark<F>(name: &str, iterations: usize, f: F) -> Duration
492    where
493        F: Fn(),
494    {
495        let timer = Timer::new();
496
497        for _ in 0..iterations {
498            let _guard = timer.start();
499            f();
500        }
501
502        let stats = timer.stats();
503        println!(
504            "Benchmark '{}': {} iterations, avg: {:?}, total: {:?}",
505            name, iterations, stats.average, stats.total
506        );
507
508        stats.average
509    }
510}
511
512/// Convenience macros
513#[macro_export]
514macro_rules! time_block {
515    ($timer:expr, $block:block) => {{
516        let _timing_guard = $timer.start();
517        $block
518    }};
519}
520
521#[macro_export]
522/// Macro to time a function call and record the result
523///
524/// # Examples
525///
526/// ```rust
527/// # use metrics_lib::time_fn;
528/// let (result, duration) = time_fn!({
529///     // Some work to time
530///     std::thread::sleep(std::time::Duration::from_millis(10));
531///     "done"
532/// });
533/// assert!(duration >= std::time::Duration::from_millis(10));
534/// assert_eq!(result, "done");
535/// ```
536macro_rules! time_fn {
537    ($func:expr) => {{
538        let start = std::time::Instant::now();
539        let result = $func;
540        let duration = start.elapsed();
541        (result, duration)
542    }};
543}
544
545#[cfg(test)]
546mod tests {
547    use super::*;
548    use std::sync::Arc;
549    use std::thread;
550
551    #[test]
552    fn test_basic_operations() {
553        let timer = Timer::new();
554
555        assert!(timer.is_empty());
556        assert_eq!(timer.count(), 0);
557        assert_eq!(timer.total(), Duration::ZERO);
558        assert_eq!(timer.average(), Duration::ZERO);
559
560        // Record a duration
561        timer.record(Duration::from_millis(100));
562
563        assert!(!timer.is_empty());
564        assert_eq!(timer.count(), 1);
565        assert!(timer.total() >= Duration::from_millis(99)); // Account for precision
566        assert!(timer.average() >= Duration::from_millis(99));
567    }
568
569    #[test]
570    fn test_running_timer() {
571        let timer = Timer::new();
572
573        {
574            let running = timer.start();
575            thread::sleep(Duration::from_millis(10));
576            assert!(running.elapsed() >= Duration::from_millis(9));
577        } // Automatically recorded when dropped
578
579        assert_eq!(timer.count(), 1);
580        assert!(timer.average() >= Duration::from_millis(9));
581    }
582
583    #[test]
584    fn test_manual_stop() {
585        let timer = Timer::new();
586
587        let running = timer.start();
588        thread::sleep(Duration::from_millis(5));
589        running.stop(); // Manual stop
590
591        assert_eq!(timer.count(), 1);
592        assert!(timer.average() >= Duration::from_millis(4));
593    }
594
595    #[test]
596    fn test_batch_recording() {
597        let timer = Timer::new();
598
599        let durations = vec![
600            Duration::from_millis(10),
601            Duration::from_millis(20),
602            Duration::from_millis(30),
603        ];
604
605        timer.record_batch(&durations);
606
607        assert_eq!(timer.count(), 3);
608        assert_eq!(timer.min(), Duration::from_millis(10));
609        assert_eq!(timer.max(), Duration::from_millis(30));
610        assert_eq!(timer.total(), Duration::from_millis(60));
611        assert_eq!(timer.average(), Duration::from_millis(20));
612    }
613
614    #[test]
615    fn test_min_max_tracking() {
616        let timer = Timer::new();
617
618        timer.record(Duration::from_millis(50));
619        timer.record(Duration::from_millis(10));
620        timer.record(Duration::from_millis(100));
621        timer.record(Duration::from_millis(25));
622
623        assert_eq!(timer.count(), 4);
624        assert_eq!(timer.min(), Duration::from_millis(10));
625        assert_eq!(timer.max(), Duration::from_millis(100));
626
627        // Check average is approximately 46.25ms (allowing for precision differences)
628        let avg = timer.average();
629        assert!(
630            avg >= Duration::from_millis(46) && avg <= Duration::from_millis(47),
631            "Average {avg:?} should be between 46ms and 47ms",
632        );
633    }
634
635    #[test]
636    fn test_reset() {
637        let timer = Timer::new();
638
639        timer.record(Duration::from_millis(100));
640        assert!(!timer.is_empty());
641
642        timer.reset();
643        assert!(timer.is_empty());
644        assert_eq!(timer.count(), 0);
645        assert_eq!(timer.total(), Duration::ZERO);
646        assert_eq!(timer.min(), Duration::ZERO);
647        assert_eq!(timer.max(), Duration::ZERO);
648    }
649
650    #[test]
651    fn test_statistics() {
652        let timer = Timer::new();
653
654        for i in 1..=10 {
655            timer.record(Duration::from_millis(i * 10));
656        }
657
658        let stats = timer.stats();
659        assert_eq!(stats.count, 10);
660        assert_eq!(stats.total, Duration::from_millis(550)); // Sum of 10+20+...+100
661        assert_eq!(stats.average, Duration::from_millis(55));
662        assert_eq!(stats.min, Duration::from_millis(10));
663        assert_eq!(stats.max, Duration::from_millis(100));
664        assert!(stats.rate_per_second > 0.0);
665        assert!(stats.age > Duration::from_nanos(0));
666    }
667
668    #[test]
669    fn test_high_concurrency() {
670        let timer = Arc::new(Timer::new());
671        let num_threads = 50;
672        let recordings_per_thread = 1000;
673
674        let handles: Vec<_> = (0..num_threads)
675            .map(|thread_id| {
676                let timer = Arc::clone(&timer);
677                thread::spawn(move || {
678                    for i in 0..recordings_per_thread {
679                        // Record varying durations
680                        let duration_ms = (thread_id * recordings_per_thread + i) % 100 + 1;
681                        timer.record(Duration::from_millis(duration_ms));
682                    }
683                })
684            })
685            .collect();
686
687        for handle in handles {
688            handle.join().unwrap();
689        }
690
691        let stats = timer.stats();
692        assert_eq!(stats.count, num_threads * recordings_per_thread);
693        assert!(stats.min > Duration::ZERO);
694        assert!(stats.max > Duration::ZERO);
695        assert!(stats.average > Duration::ZERO);
696        assert!(stats.rate_per_second > 0.0);
697    }
698
699    #[test]
700    fn test_concurrent_timing() {
701        let timer = Arc::new(Timer::new());
702        let num_threads = 20;
703
704        let handles: Vec<_> = (0..num_threads)
705            .map(|_| {
706                let timer = Arc::clone(&timer);
707                thread::spawn(move || {
708                    for _ in 0..100 {
709                        let _guard = timer.start();
710                        thread::sleep(Duration::from_micros(100)); // Very short sleep
711                    }
712                })
713            })
714            .collect();
715
716        for handle in handles {
717            handle.join().unwrap();
718        }
719
720        let stats = timer.stats();
721        assert_eq!(stats.count, num_threads * 100);
722        assert!(stats.average >= Duration::from_micros(50)); // Should be at least 50μs
723    }
724
725    #[test]
726    fn test_utility_functions() {
727        // Test time_fn
728        let (result, duration) = utils::time_fn(|| {
729            thread::sleep(Duration::from_millis(10));
730            42
731        });
732
733        assert_eq!(result, 42);
734        assert!(duration >= Duration::from_millis(9));
735
736        // Test time_and_record
737        let timer = Timer::new();
738        let result = utils::time_and_record(&timer, || {
739            thread::sleep(Duration::from_millis(5));
740            "hello"
741        });
742
743        assert_eq!(result, "hello");
744        assert_eq!(timer.count(), 1);
745        assert!(timer.average() >= Duration::from_millis(4));
746
747        // Test benchmark
748        let avg_duration = utils::benchmark("test_function", 10, || {
749            thread::sleep(Duration::from_millis(1));
750        });
751
752        assert!(avg_duration >= Duration::from_millis(1));
753    }
754
755    #[test]
756    fn test_macros() {
757        let timer = Timer::new();
758
759        // Test time_block macro
760        let result = time_block!(timer, {
761            thread::sleep(Duration::from_millis(5));
762            "result"
763        });
764
765        assert_eq!(result, "result");
766        assert_eq!(timer.count(), 1);
767
768        // Test time_fn macro
769        let (result, duration) = time_fn!({
770            thread::sleep(Duration::from_millis(2));
771            100
772        });
773
774        assert_eq!(result, 100);
775        assert!(duration >= Duration::from_millis(1));
776    }
777
778    #[test]
779    fn test_display_and_debug() {
780        let timer = Timer::new();
781        timer.record(Duration::from_millis(100));
782
783        let display_str = format!("{timer}");
784        assert!(display_str.contains("Timer"));
785        assert!(display_str.contains("count: 1"));
786
787        let debug_str = format!("{timer:?}");
788        assert!(debug_str.contains("Timer"));
789        assert!(debug_str.contains("count"));
790        assert!(debug_str.contains("average"));
791    }
792
793    #[test]
794    fn test_empty_batch_handling() {
795        let timer = Timer::new();
796        timer.record_batch(&[]);
797        assert!(timer.is_empty());
798
799        assert!(timer.try_record_batch(&[]).is_ok());
800        assert!(timer.is_empty());
801    }
802
803    #[test]
804    fn test_nested_timers_and_rate() {
805        let timer = Timer::new();
806
807        {
808            let _outer = timer.start();
809            thread::sleep(Duration::from_millis(2));
810            {
811                let _inner = timer.start();
812                thread::sleep(Duration::from_millis(2));
813            } // inner drop -> record
814        } // outer drop -> record
815
816        // Two recordings (outer + inner)
817        assert_eq!(timer.count(), 2);
818
819        // Non-zero rate per second (age should be > 0)
820        let rate = timer.rate_per_second();
821        assert!(rate >= 0.0);
822
823        // stats.rate_per_second should mirror rate_per_second()
824        let stats = timer.stats();
825        assert!(stats.rate_per_second >= 0.0);
826    }
827}
828
829#[cfg(all(test, feature = "bench-tests", not(tarpaulin)))]
830#[allow(unused_imports)]
831mod benchmarks {
832    use super::*;
833    use std::time::Instant;
834
835    #[cfg_attr(not(feature = "bench-tests"), ignore)]
836    #[test]
837    fn bench_timer_record() {
838        let timer = Timer::new();
839        let duration = Duration::from_nanos(1000);
840        let iterations = 1_000_000;
841
842        let start = Instant::now();
843        for _ in 0..iterations {
844            timer.record(duration);
845        }
846        let elapsed = start.elapsed();
847
848        println!(
849            "Timer record: {:.2} ns/op",
850            elapsed.as_nanos() as f64 / iterations as f64
851        );
852
853        assert_eq!(timer.count(), iterations);
854        // Should be under 300ns per record (relaxed from 200ns)
855        assert!(elapsed.as_nanos() / (iterations as u128) < 300);
856    }
857
858    #[cfg_attr(not(feature = "bench-tests"), ignore)]
859    #[test]
860    fn bench_running_timer() {
861        let timer = Timer::new();
862        let iterations = 100_000;
863
864        let start = Instant::now();
865        for _ in 0..iterations {
866            let guard = timer.start();
867            // Do minimal work
868            let _ = guard.elapsed();
869            guard.stop();
870        }
871        let elapsed = start.elapsed();
872
873        println!(
874            "Running timer: {:.2} ns/op",
875            elapsed.as_nanos() as f64 / iterations as f64
876        );
877
878        assert_eq!(timer.count(), iterations);
879        // Should be under 1500ns per timer operation (relaxed from 1000ns)
880        assert!(elapsed.as_nanos() / (iterations as u128) < 1500);
881    }
882
883    #[cfg_attr(not(feature = "bench-tests"), ignore)]
884    #[test]
885    fn bench_timer_stats() {
886        let timer = Timer::new();
887
888        // Fill timer with data
889        for i in 0..1000 {
890            timer.record(Duration::from_nanos(i * 1000));
891        }
892
893        let iterations = 1_000_000;
894        let start = Instant::now();
895
896        for _ in 0..iterations {
897            let _ = timer.stats();
898        }
899
900        let elapsed = start.elapsed();
901        println!(
902            "Timer stats: {:.2} ns/op",
903            elapsed.as_nanos() as f64 / iterations as f64
904        );
905
906        // Should be very fast since it's just atomic loads (relaxed from 100ns to 300ns)
907        assert!(elapsed.as_nanos() / iterations < 300);
908    }
909}