Skip to main content

slain_num/
overrides.rs

1use crate::{simd, stats};
2
3pub trait Dispatch {
4    fn sum(&self, x: &[f64]) -> f64 {
5        simd::sum(x)
6    }
7
8    fn mean(&self, x: &[f64]) -> f64 {
9        stats::mean(x)
10    }
11
12    fn variance(&self, x: &[f64]) -> f64 {
13        stats::variance(x)
14    }
15}
16
17pub struct Core;
18
19impl Dispatch for Core {}
20
21#[cfg(test)]
22mod tests {
23    use super::*;
24    use std::cell::RefCell;
25    use std::time::Instant;
26
27    struct Layer {
28        seen: RefCell<Vec<&'static str>>,
29    }
30
31    impl Dispatch for Layer {
32        fn sum(&self, _x: &[f64]) -> f64 {
33            self.seen.borrow_mut().push("sum");
34            -1.0
35        }
36
37        fn mean(&self, x: &[f64]) -> f64 {
38            self.seen.borrow_mut().push("mean");
39            Core.mean(x)
40        }
41    }
42
43    #[test]
44    fn layer_handles_falls_through_and_leaves_core_unchanged() {
45        let x: Vec<f64> = (0..5).map(f64::from).collect();
46        let layer = Layer { seen: RefCell::new(Vec::new()) };
47        assert_eq!(Core.sum(&x), 10.0);
48        assert_eq!(layer.sum(&x), -1.0);
49        assert_eq!(layer.mean(&x), 2.0);
50        assert_eq!(layer.variance(&x), stats::variance(&x));
51        assert_eq!(Core.sum(&x), 10.0);
52        let core_dyn: &dyn Dispatch = &Core;
53        let layer_dyn: &dyn Dispatch = &layer;
54        assert_eq!(core_dyn.sum(&x), 10.0);
55        assert_eq!(layer_dyn.sum(&x), -1.0);
56        assert_eq!(*layer.seen.borrow(), ["sum", "mean", "sum"]);
57    }
58
59    fn calls_per_second(mut f: impl FnMut() -> f64) -> f64 {
60        let reps = 2000u32;
61        let mut best = f64::MAX;
62        for _ in 0..21 {
63            let t = Instant::now();
64            for _ in 0..reps {
65                crate::bench::slain(f());
66            }
67            best = best.min(t.elapsed().as_secs_f64());
68        }
69        f64::from(reps) / best
70    }
71
72    #[test]
73    #[ignore]
74    fn time_dispatch() {
75        let x: Vec<f64> = (0..4096).map(|i| f64::from(i) * 0.5).collect();
76        let layer = Layer { seen: RefCell::new(Vec::new()) };
77        let core_dyn: &dyn Dispatch = &Core;
78        let direct = calls_per_second(|| stats::mean(crate::bench::slain(&x)));
79        let fixed = calls_per_second(|| Core.mean(crate::bench::slain(&x)));
80        let dynamic = calls_per_second(|| crate::bench::slain(core_dyn).mean(crate::bench::slain(&x)));
81        let through = calls_per_second(|| {
82            layer.seen.borrow_mut().clear();
83            layer.mean(crate::bench::slain(&x))
84        });
85        for (name, c) in [("direct stats::mean", direct), ("static Core.mean", fixed), ("dyn Dispatch mean (Core)", dynamic), ("layer fall-through mean", through)] {
86            println!("DISPATCH {name:28} {c:.9} calls/s  {:.9}x direct", c / direct);
87        }
88    }
89}