Skip to main content

fluxbench_ipc/
throughput.rs

1//! Work per routine call, for throughput rates.
2
3use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize};
4
5/// Work one routine call processes.
6///
7/// The report divides it by the mean time per call to get a rate per second.
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Archive, RkyvSerialize, RkyvDeserialize)]
9pub enum Throughput {
10    /// Bytes per call. Reports show binary units such as MiB/s.
11    Bytes(u64),
12    /// Elements per call, such as items, records, or tokens.
13    Elements(u64),
14}
15
16impl Throughput {
17    /// Rate per second at `mean_ns` per call. `None` for a mean at or below 0.
18    pub fn per_second(self, mean_ns: f64) -> Option<f64> {
19        let amount = match self {
20            Throughput::Bytes(n) | Throughput::Elements(n) => n as f64,
21        };
22        (mean_ns.is_finite() && mean_ns > 0.0).then(|| amount * 1e9 / mean_ns)
23    }
24}
25
26#[cfg(test)]
27mod tests {
28    use super::*;
29    use rkyv::rancor;
30
31    #[test]
32    fn per_second_scales_by_mean() {
33        assert_eq!(
34            Throughput::Bytes(1024).per_second(1_000.0),
35            Some(1_024_000_000.0)
36        );
37        assert_eq!(Throughput::Elements(4).per_second(2.0), Some(2e9));
38    }
39
40    #[test]
41    fn per_second_rejects_zero_and_bad_means() {
42        assert_eq!(Throughput::Bytes(8).per_second(0.0), None);
43        assert_eq!(Throughput::Bytes(8).per_second(-1.0), None);
44        assert_eq!(Throughput::Bytes(8).per_second(f64::NAN), None);
45        assert_eq!(Throughput::Bytes(8).per_second(f64::INFINITY), None);
46    }
47
48    #[test]
49    fn rkyv_roundtrip() {
50        for original in [Throughput::Bytes(7), Throughput::Elements(u64::MAX)] {
51            let bytes = rkyv::to_bytes::<rancor::Error>(&original).unwrap();
52            let decoded = rkyv::from_bytes::<Throughput, rancor::Error>(&bytes).unwrap();
53            assert_eq!(original, decoded);
54        }
55    }
56}