bench/
stats.rs

1use std::time::Duration;
2
3use hdrhistogram::Histogram;
4
5#[derive(Default)]
6pub struct Stats {
7    pub total_size: u64,
8    pub total_duration: Duration,
9    pub streams: usize,
10    pub stream_stats: StreamStats,
11}
12
13impl Stats {
14    pub fn stream_finished(&mut self, stream_result: TransferResult) {
15        self.total_size += stream_result.size;
16        self.streams += 1;
17
18        self.stream_stats
19            .duration_hist
20            .record(stream_result.duration.as_millis() as u64)
21            .unwrap();
22        self.stream_stats
23            .throughput_hist
24            .record(stream_result.throughput as u64)
25            .unwrap();
26    }
27
28    pub fn print(&self, stat_name: &str) {
29        println!("Overall {stat_name} stats:\n");
30        println!(
31            "Transferred {} bytes on {} streams in {:4.2?} ({:.2} MiB/s)\n",
32            self.total_size,
33            self.streams,
34            self.total_duration,
35            throughput_bps(self.total_duration, self.total_size) / 1024.0 / 1024.0
36        );
37
38        println!("Stream {stat_name} metrics:\n");
39
40        println!("      │  Throughput   │ Duration ");
41        println!("──────┼───────────────┼──────────");
42
43        let print_metric = |label: &'static str, get_metric: fn(&Histogram<u64>) -> u64| {
44            println!(
45                " {} │ {:7.2} MiB/s │ {:>9.2?}",
46                label,
47                get_metric(&self.stream_stats.throughput_hist) as f64 / 1024.0 / 1024.0,
48                Duration::from_millis(get_metric(&self.stream_stats.duration_hist))
49            );
50        };
51
52        print_metric("AVG ", |hist| hist.mean() as u64);
53        print_metric("P0  ", |hist| hist.value_at_quantile(0.00));
54        print_metric("P10 ", |hist| hist.value_at_quantile(0.10));
55        print_metric("P50 ", |hist| hist.value_at_quantile(0.50));
56        print_metric("P90 ", |hist| hist.value_at_quantile(0.90));
57        print_metric("P100", |hist| hist.value_at_quantile(1.00));
58    }
59}
60
61pub struct StreamStats {
62    pub duration_hist: Histogram<u64>,
63    pub throughput_hist: Histogram<u64>,
64}
65
66impl Default for StreamStats {
67    fn default() -> Self {
68        Self {
69            duration_hist: Histogram::<u64>::new(3).unwrap(),
70            throughput_hist: Histogram::<u64>::new(3).unwrap(),
71        }
72    }
73}
74
75#[derive(Debug)]
76pub struct TransferResult {
77    pub duration: Duration,
78    pub size: u64,
79    pub throughput: f64,
80}
81
82impl TransferResult {
83    pub fn new(duration: Duration, size: u64) -> Self {
84        let throughput = throughput_bps(duration, size);
85        Self {
86            duration,
87            size,
88            throughput,
89        }
90    }
91}
92
93pub fn throughput_bps(duration: Duration, size: u64) -> f64 {
94    (size as f64) / (duration.as_secs_f64())
95}