windjammer_runtime/bench.rs
1//! Benchmarking utilities for Windjammer tests
2//!
3//! Provides simple benchmarking functions that can be used with `@bench` decorator.
4//! For more advanced benchmarking, use the criterion crate directly.
5
6use std::time::{Duration, Instant};
7
8/// Run a closure multiple times and return the average duration
9///
10/// # Example
11/// ```
12/// use windjammer_runtime::bench::bench_iterations;
13///
14/// let avg = bench_iterations(1000, || {
15/// // Code to benchmark
16/// let _ = (0..100).sum::<i32>();
17/// });
18///
19/// println!("Average time: {:?}", avg);
20/// ```
21pub fn bench_iterations<F: Fn()>(iterations: usize, f: F) -> Duration {
22 let mut total = Duration::ZERO;
23
24 // Warmup
25 for _ in 0..10 {
26 f();
27 }
28
29 // Actual benchmark
30 for _ in 0..iterations {
31 let start = Instant::now();
32 f();
33 total += start.elapsed();
34 }
35
36 total / iterations as u32
37}
38
39/// Benchmark a closure and return its duration
40///
41/// # Example
42/// ```
43/// use windjammer_runtime::bench::bench;
44///
45/// let duration = bench(|| {
46/// // Code to benchmark
47/// let _ = (0..1000).sum::<i32>();
48/// });
49///
50/// println!("Duration: {:?}", duration);
51/// ```
52pub fn bench<F: FnOnce()>(f: F) -> Duration {
53 let start = Instant::now();
54 f();
55 start.elapsed()
56}
57
58/// Compare two implementations and return their relative performance
59///
60/// # Example
61/// ```
62/// use windjammer_runtime::bench::bench_compare;
63///
64/// let (time_a, time_b, speedup) = bench_compare(
65/// || {
66/// // Old implementation
67/// let _ = (0..1000).sum::<i32>();
68/// },
69/// || {
70/// // New implementation
71/// let _ = (0..1000).fold(0, |acc, x| acc + x);
72/// },
73/// 100, // iterations
74/// );
75///
76/// println!("Old: {:?}, New: {:?}, Speedup: {:.2}x", time_a, time_b, speedup);
77/// ```
78pub fn bench_compare<F: Fn(), G: Fn()>(f: F, g: G, iterations: usize) -> (Duration, Duration, f64) {
79 let time_f = bench_iterations(iterations, f);
80 let time_g = bench_iterations(iterations, g);
81
82 let speedup = time_f.as_secs_f64() / time_g.as_secs_f64();
83
84 (time_f, time_g, speedup)
85}
86
87#[cfg(test)]
88mod tests {
89 use super::*;
90 use std::thread;
91
92 #[test]
93 fn test_bench_iterations() {
94 let avg = bench_iterations(10, || {
95 thread::sleep(Duration::from_millis(1));
96 });
97
98 // Should be around 1ms (with some variance)
99 assert!(avg.as_millis() >= 1 && avg.as_millis() <= 5);
100 }
101
102 #[test]
103 fn test_bench() {
104 let duration = bench(|| {
105 thread::sleep(Duration::from_millis(10));
106 });
107
108 // Should be around 10ms
109 assert!(duration.as_millis() >= 10 && duration.as_millis() <= 20);
110 }
111
112 #[test]
113 #[cfg_attr(tarpaulin, ignore)]
114 fn test_bench_compare() {
115 // Test that bench_compare returns reasonable measurements
116 // Note: We can't reliably test timing relationships in CI due to
117 // thread scheduling variance, so just verify the function works
118 // This test is ignored in tarpaulin because coverage instrumentation
119 // adds overhead that makes timing measurements unreliable
120 let (time_slow, time_fast, speedup) = bench_compare(
121 || {
122 // Use busy-wait instead of sleep for more deterministic timing
123 let start = std::time::Instant::now();
124 let mut sum = 0u64;
125 while start.elapsed() < Duration::from_micros(100) {
126 sum = sum.wrapping_add(1);
127 }
128 },
129 || {
130 // Shorter busy-wait
131 let start = std::time::Instant::now();
132 let mut sum = 0u64;
133 while start.elapsed() < Duration::from_micros(50) {
134 sum = sum.wrapping_add(1);
135 }
136 },
137 3,
138 );
139
140 // Just verify we got reasonable measurements (not zero, not absurd)
141 assert!(
142 time_slow > Duration::from_nanos(1),
143 "Slow function should take measurable time, got {:?}",
144 time_slow
145 );
146 assert!(
147 time_fast > Duration::from_nanos(1),
148 "Fast function should take measurable time, got {:?}",
149 time_fast
150 );
151 assert!(
152 speedup > 0.0 && speedup < 1000.0,
153 "Speedup should be reasonable, got {}",
154 speedup
155 );
156 }
157}