1use std::sync::atomic::{AtomicU64, Ordering};
14use std::time::{Duration, Instant};
15
16#[repr(align(64))]
21pub struct Timer {
22 count: AtomicU64,
24 total_nanos: AtomicU64,
26 min_nanos: AtomicU64,
28 max_nanos: AtomicU64,
30 created_at: Instant,
32}
33
34pub struct RunningTimer<'a> {
38 timer: &'a Timer,
39 start_time: Instant,
40 stopped: bool,
41}
42
43#[derive(Debug, Clone)]
45pub struct TimerStats {
46 pub count: u64,
48 pub total: Duration,
50 pub average: Duration,
52 pub min: Duration,
54 pub max: Duration,
56 pub age: Duration,
58 pub rate_per_second: f64,
60}
61
62impl Timer {
63 #[inline]
65 pub fn new() -> Self {
66 Self {
67 count: AtomicU64::new(0),
68 total_nanos: AtomicU64::new(0),
69 min_nanos: AtomicU64::new(u64::MAX),
70 max_nanos: AtomicU64::new(0),
71 created_at: Instant::now(),
72 }
73 }
74
75 #[inline(always)]
77 pub fn start(&self) -> RunningTimer<'_> {
78 RunningTimer {
79 timer: self,
80 start_time: Instant::now(),
81 stopped: false,
82 }
83 }
84
85 #[inline]
87 pub fn record(&self, duration: Duration) {
88 let duration_ns = duration.as_nanos() as u64;
89 self.record_ns(duration_ns);
90 }
91
92 #[inline(always)]
94 pub fn record_ns(&self, duration_ns: u64) {
95 self.total_nanos.fetch_add(duration_ns, Ordering::Relaxed);
97 self.count.fetch_add(1, Ordering::Relaxed);
98
99 self.update_min(duration_ns);
101
102 self.update_max(duration_ns);
104 }
105
106 #[inline]
108 pub fn record_batch(&self, durations: &[Duration]) {
109 if durations.is_empty() {
110 return;
111 }
112
113 let mut total_ns = 0u64;
114 let mut local_min = u64::MAX;
115 let mut local_max = 0u64;
116
117 for duration in durations {
118 let ns = duration.as_nanos() as u64;
119 total_ns += ns;
120 local_min = local_min.min(ns);
121 local_max = local_max.max(ns);
122 }
123
124 self.total_nanos.fetch_add(total_ns, Ordering::Relaxed);
125 self.count.fetch_add(durations.len() as u64, Ordering::Relaxed);
126
127 if local_min < u64::MAX {
128 self.update_min(local_min);
129 }
130 if local_max > 0 {
131 self.update_max(local_max);
132 }
133 }
134
135 #[inline(always)]
137 pub fn count(&self) -> u64 {
138 self.count.load(Ordering::Relaxed)
139 }
140
141 #[inline]
143 pub fn total(&self) -> Duration {
144 Duration::from_nanos(self.total_nanos.load(Ordering::Relaxed))
145 }
146
147 #[inline]
149 pub fn average(&self) -> Duration {
150 let count = self.count();
151 if count == 0 {
152 return Duration::ZERO;
153 }
154
155 let total_ns = self.total_nanos.load(Ordering::Relaxed);
156 Duration::from_nanos(total_ns / count)
157 }
158
159 #[inline]
161 pub fn min(&self) -> Duration {
162 let min_ns = self.min_nanos.load(Ordering::Relaxed);
163 if min_ns == u64::MAX {
164 Duration::ZERO
165 } else {
166 Duration::from_nanos(min_ns)
167 }
168 }
169
170 #[inline]
172 pub fn max(&self) -> Duration {
173 Duration::from_nanos(self.max_nanos.load(Ordering::Relaxed))
174 }
175
176 #[inline]
178 pub fn reset(&self) {
179 self.total_nanos.store(0, Ordering::SeqCst);
180 self.count.store(0, Ordering::SeqCst);
181 self.min_nanos.store(u64::MAX, Ordering::SeqCst);
182 self.max_nanos.store(0, Ordering::SeqCst);
183 }
184
185 pub fn stats(&self) -> TimerStats {
187 let count = self.count();
188 let total_ns = self.total_nanos.load(Ordering::Relaxed);
189 let min_ns = self.min_nanos.load(Ordering::Relaxed);
190 let max_ns = self.max_nanos.load(Ordering::Relaxed);
191
192 let total = Duration::from_nanos(total_ns);
193 let average = if count > 0 {
194 Duration::from_nanos(total_ns / count)
195 } else {
196 Duration::ZERO
197 };
198
199 let min = if min_ns == u64::MAX {
200 Duration::ZERO
201 } else {
202 Duration::from_nanos(min_ns)
203 };
204
205 let max = Duration::from_nanos(max_ns);
206 let age = self.created_at.elapsed();
207
208 let rate_per_second = if age.as_secs_f64() > 0.0 {
209 count as f64 / age.as_secs_f64()
210 } else {
211 0.0
212 };
213
214 TimerStats {
215 count,
216 total,
217 average,
218 min,
219 max,
220 age,
221 rate_per_second,
222 }
223 }
224
225 #[inline]
227 pub fn age(&self) -> Duration {
228 self.created_at.elapsed()
229 }
230
231 #[inline]
233 pub fn is_empty(&self) -> bool {
234 self.count() == 0
235 }
236
237 #[inline]
239 pub fn rate_per_second(&self) -> f64 {
240 let age_seconds = self.age().as_secs_f64();
241 if age_seconds > 0.0 {
242 self.count() as f64 / age_seconds
243 } else {
244 0.0
245 }
246 }
247
248 #[inline(always)]
251 fn update_min(&self, value: u64) {
252 loop {
253 let current = self.min_nanos.load(Ordering::Relaxed);
254 if value >= current {
255 break; }
257
258 match self.min_nanos.compare_exchange_weak(
259 current,
260 value,
261 Ordering::Relaxed,
262 Ordering::Relaxed,
263 ) {
264 Ok(_) => break,
265 Err(_) => continue, }
267 }
268 }
269
270 #[inline(always)]
271 fn update_max(&self, value: u64) {
272 loop {
273 let current = self.max_nanos.load(Ordering::Relaxed);
274 if value <= current {
275 break; }
277
278 match self.max_nanos.compare_exchange_weak(
279 current,
280 value,
281 Ordering::Relaxed,
282 Ordering::Relaxed,
283 ) {
284 Ok(_) => break,
285 Err(_) => continue, }
287 }
288 }
289}
290
291impl Default for Timer {
292 #[inline]
293 fn default() -> Self {
294 Self::new()
295 }
296}
297
298impl std::fmt::Display for Timer {
299 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
300 let stats = self.stats();
301 write!(f, "Timer(count: {}, avg: {:?})", stats.count, stats.average)
302 }
303}
304
305impl std::fmt::Debug for Timer {
306 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
307 let stats = self.stats();
308 f.debug_struct("Timer")
309 .field("count", &stats.count)
310 .field("total", &stats.total)
311 .field("average", &stats.average)
312 .field("min", &stats.min)
313 .field("max", &stats.max)
314 .field("rate_per_second", &stats.rate_per_second)
315 .finish()
316 }
317}
318
319unsafe impl Send for Timer {}
321unsafe impl Sync for Timer {}
322
323impl<'a> RunningTimer<'a> {
325 #[inline]
327 pub fn elapsed(&self) -> Duration {
328 self.start_time.elapsed()
329 }
330
331 #[inline]
333 pub fn stop(mut self) {
334 if !self.stopped {
335 let elapsed = self.start_time.elapsed();
336 self.timer.record(elapsed);
337 self.stopped = true;
338 }
339 }
341}
342
343impl<'a> Drop for RunningTimer<'a> {
344 #[inline]
345 fn drop(&mut self) {
346 if !self.stopped {
347 let elapsed = self.start_time.elapsed();
348 self.timer.record(elapsed);
349 }
350 }
351}
352
353pub mod utils {
355 use super::*;
356
357 #[inline]
359 pub fn time_fn<T>(f: impl FnOnce() -> T) -> (T, Duration) {
360 let start = Instant::now();
361 let result = f();
362 let duration = start.elapsed();
363 (result, duration)
364 }
365
366 #[inline]
368 pub fn time_and_record<T>(timer: &Timer, f: impl FnOnce() -> T) -> T {
369 let _timing_guard = timer.start();
370 f() }
372
373 #[inline]
375 pub fn scoped_timer(timer: &Timer) -> RunningTimer<'_> {
376 timer.start()
377 }
378
379 pub fn benchmark<F>(name: &str, iterations: usize, f: F) -> Duration
381 where
382 F: Fn(),
383 {
384 let timer = Timer::new();
385
386 for _ in 0..iterations {
387 let _guard = timer.start();
388 f();
389 }
390
391 let stats = timer.stats();
392 println!("Benchmark '{}': {} iterations, avg: {:?}, total: {:?}",
393 name, iterations, stats.average, stats.total);
394
395 stats.average
396 }
397}
398
399#[macro_export]
401macro_rules! time_block {
402 ($timer:expr, $block:block) => {{
403 let _timing_guard = $timer.start();
404 $block
405 }};
406}
407
408#[macro_export]
409macro_rules! time_fn {
424 ($func:expr) => {{
425 let start = std::time::Instant::now();
426 let result = $func;
427 let duration = start.elapsed();
428 (result, duration)
429 }};
430}
431
432#[cfg(test)]
433mod tests {
434 use super::*;
435 use std::sync::Arc;
436 use std::thread;
437
438 #[test]
439 fn test_basic_operations() {
440 let timer = Timer::new();
441
442 assert!(timer.is_empty());
443 assert_eq!(timer.count(), 0);
444 assert_eq!(timer.total(), Duration::ZERO);
445 assert_eq!(timer.average(), Duration::ZERO);
446
447 timer.record(Duration::from_millis(100));
449
450 assert!(!timer.is_empty());
451 assert_eq!(timer.count(), 1);
452 assert!(timer.total() >= Duration::from_millis(99)); assert!(timer.average() >= Duration::from_millis(99));
454 }
455
456 #[test]
457 fn test_running_timer() {
458 let timer = Timer::new();
459
460 {
461 let running = timer.start();
462 thread::sleep(Duration::from_millis(10));
463 assert!(running.elapsed() >= Duration::from_millis(9));
464 } assert_eq!(timer.count(), 1);
467 assert!(timer.average() >= Duration::from_millis(9));
468 }
469
470 #[test]
471 fn test_manual_stop() {
472 let timer = Timer::new();
473
474 let running = timer.start();
475 thread::sleep(Duration::from_millis(5));
476 running.stop(); assert_eq!(timer.count(), 1);
479 assert!(timer.average() >= Duration::from_millis(4));
480 }
481
482 #[test]
483 fn test_batch_recording() {
484 let timer = Timer::new();
485
486 let durations = vec![
487 Duration::from_millis(10),
488 Duration::from_millis(20),
489 Duration::from_millis(30),
490 ];
491
492 timer.record_batch(&durations);
493
494 assert_eq!(timer.count(), 3);
495 assert_eq!(timer.min(), Duration::from_millis(10));
496 assert_eq!(timer.max(), Duration::from_millis(30));
497 assert_eq!(timer.total(), Duration::from_millis(60));
498 assert_eq!(timer.average(), Duration::from_millis(20));
499 }
500
501 #[test]
502 fn test_min_max_tracking() {
503 let timer = Timer::new();
504
505 timer.record(Duration::from_millis(50));
506 timer.record(Duration::from_millis(10));
507 timer.record(Duration::from_millis(100));
508 timer.record(Duration::from_millis(25));
509
510 assert_eq!(timer.count(), 4);
511 assert_eq!(timer.min(), Duration::from_millis(10));
512 assert_eq!(timer.max(), Duration::from_millis(100));
513
514 let avg = timer.average();
516 assert!(avg >= Duration::from_millis(46) && avg <= Duration::from_millis(47),
517 "Average {:?} should be between 46ms and 47ms", avg);
518 }
519
520 #[test]
521 fn test_reset() {
522 let timer = Timer::new();
523
524 timer.record(Duration::from_millis(100));
525 assert!(!timer.is_empty());
526
527 timer.reset();
528 assert!(timer.is_empty());
529 assert_eq!(timer.count(), 0);
530 assert_eq!(timer.total(), Duration::ZERO);
531 assert_eq!(timer.min(), Duration::ZERO);
532 assert_eq!(timer.max(), Duration::ZERO);
533 }
534
535 #[test]
536 fn test_statistics() {
537 let timer = Timer::new();
538
539 for i in 1..=10 {
540 timer.record(Duration::from_millis(i * 10));
541 }
542
543 let stats = timer.stats();
544 assert_eq!(stats.count, 10);
545 assert_eq!(stats.total, Duration::from_millis(550)); assert_eq!(stats.average, Duration::from_millis(55));
547 assert_eq!(stats.min, Duration::from_millis(10));
548 assert_eq!(stats.max, Duration::from_millis(100));
549 assert!(stats.rate_per_second > 0.0);
550 assert!(stats.age > Duration::from_nanos(0));
551 }
552
553 #[test]
554 fn test_high_concurrency() {
555 let timer = Arc::new(Timer::new());
556 let num_threads = 50;
557 let recordings_per_thread = 1000;
558
559 let handles: Vec<_> = (0..num_threads)
560 .map(|thread_id| {
561 let timer = Arc::clone(&timer);
562 thread::spawn(move || {
563 for i in 0..recordings_per_thread {
564 let duration_ms = (thread_id * recordings_per_thread + i) % 100 + 1;
566 timer.record(Duration::from_millis(duration_ms as u64));
567 }
568 })
569 })
570 .collect();
571
572 for handle in handles {
573 handle.join().unwrap();
574 }
575
576 let stats = timer.stats();
577 assert_eq!(stats.count, num_threads * recordings_per_thread);
578 assert!(stats.min > Duration::ZERO);
579 assert!(stats.max > Duration::ZERO);
580 assert!(stats.average > Duration::ZERO);
581 assert!(stats.rate_per_second > 0.0);
582 }
583
584 #[test]
585 fn test_concurrent_timing() {
586 let timer = Arc::new(Timer::new());
587 let num_threads = 20;
588
589 let handles: Vec<_> = (0..num_threads)
590 .map(|_| {
591 let timer = Arc::clone(&timer);
592 thread::spawn(move || {
593 for _ in 0..100 {
594 let _guard = timer.start();
595 thread::sleep(Duration::from_micros(100)); }
597 })
598 })
599 .collect();
600
601 for handle in handles {
602 handle.join().unwrap();
603 }
604
605 let stats = timer.stats();
606 assert_eq!(stats.count, num_threads * 100);
607 assert!(stats.average >= Duration::from_micros(50)); }
609
610 #[test]
611 fn test_utility_functions() {
612 let (result, duration) = utils::time_fn(|| {
614 thread::sleep(Duration::from_millis(10));
615 42
616 });
617
618 assert_eq!(result, 42);
619 assert!(duration >= Duration::from_millis(9));
620
621 let timer = Timer::new();
623 let result = utils::time_and_record(&timer, || {
624 thread::sleep(Duration::from_millis(5));
625 "hello"
626 });
627
628 assert_eq!(result, "hello");
629 assert_eq!(timer.count(), 1);
630 assert!(timer.average() >= Duration::from_millis(4));
631
632 let avg_duration = utils::benchmark("test_function", 10, || {
634 thread::sleep(Duration::from_millis(1));
635 });
636
637 assert!(avg_duration >= Duration::from_millis(1));
638 }
639
640 #[test]
641 fn test_macros() {
642 let timer = Timer::new();
643
644 let result = time_block!(timer, {
646 thread::sleep(Duration::from_millis(5));
647 "result"
648 });
649
650 assert_eq!(result, "result");
651 assert_eq!(timer.count(), 1);
652
653 let (result, duration) = time_fn!({
655 thread::sleep(Duration::from_millis(2));
656 100
657 });
658
659 assert_eq!(result, 100);
660 assert!(duration >= Duration::from_millis(1));
661 }
662
663 #[test]
664 fn test_display_and_debug() {
665 let timer = Timer::new();
666 timer.record(Duration::from_millis(100));
667
668 let display_str = format!("{}", timer);
669 assert!(display_str.contains("Timer"));
670 assert!(display_str.contains("count: 1"));
671
672 let debug_str = format!("{:?}", timer);
673 assert!(debug_str.contains("Timer"));
674 assert!(debug_str.contains("count"));
675 assert!(debug_str.contains("average"));
676 }
677}
678
679#[cfg(test)]
680mod benchmarks {
681 use super::*;
682 use std::time::Instant;
683
684 #[test]
685 fn bench_timer_record() {
686 let timer = Timer::new();
687 let duration = Duration::from_nanos(1000);
688 let iterations = 1_000_000;
689
690 let start = Instant::now();
691 for _ in 0..iterations {
692 timer.record(duration);
693 }
694 let elapsed = start.elapsed();
695
696 println!("Timer record: {:.2} ns/op",
697 elapsed.as_nanos() as f64 / iterations as f64);
698
699 assert_eq!(timer.count(), iterations);
700 assert!(elapsed.as_nanos() / (iterations as u128) < 300);
702 }
703
704 #[test]
705 fn bench_running_timer() {
706 let timer = Timer::new();
707 let iterations = 100_000;
708
709 let start = Instant::now();
710 for _ in 0..iterations {
711 let guard = timer.start();
712 let _ = guard.elapsed();
714 guard.stop();
715 }
716 let elapsed = start.elapsed();
717
718 println!("Running timer: {:.2} ns/op",
719 elapsed.as_nanos() as f64 / iterations as f64);
720
721 assert_eq!(timer.count(), iterations);
722 assert!(elapsed.as_nanos() / (iterations as u128) < 1500);
724 }
725
726 #[test]
727 fn bench_timer_stats() {
728 let timer = Timer::new();
729
730 for i in 0..1000 {
732 timer.record(Duration::from_nanos(i * 1000));
733 }
734
735 let iterations = 1_000_000;
736 let start = Instant::now();
737
738 for _ in 0..iterations {
739 let _ = timer.stats();
740 }
741
742 let elapsed = start.elapsed();
743 println!("Timer stats: {:.2} ns/op",
744 elapsed.as_nanos() as f64 / iterations as f64);
745
746 assert!(elapsed.as_nanos() / iterations < 300);
748 }
749}