Skip to main content

streaming_crypto/core_api/benchmarks/
bench_summary.rs

1use crate::benchmarks::bench_results::BenchmarkResult;
2use serde_json::json;
3use std::collections::HashMap;
4
5#[derive(Debug)]
6pub struct Summary {
7    pub total_tests: usize,
8    pub avg_throughput_mb_s: f64,
9    pub min_throughput_mb_s: f64,
10    pub max_throughput_mb_s: f64,
11    pub avg_latency_ms: f64,
12    pub stddev_latency_ms: f64,
13}
14
15impl Summary {
16    pub fn to_json_map(&self) -> HashMap<String, serde_json::Value> {
17        let mut map = HashMap::new();
18        map.insert("total_tests".to_string(), json!(self.total_tests));
19        map.insert("avg_throughput_mb_s".to_string(), json!(self.avg_throughput_mb_s));
20        map.insert("min_throughput_mb_s".to_string(), json!(self.min_throughput_mb_s));
21        map.insert("max_throughput_mb_s".to_string(), json!(self.max_throughput_mb_s));
22        map.insert("avg_latency_ms".to_string(), json!(self.avg_latency_ms));
23        map.insert("stddev_latency_ms".to_string(), json!(self.stddev_latency_ms));
24        map
25    }
26}
27
28pub fn compute_summary(results: &[BenchmarkResult]) -> Summary {
29    let throughputs: Vec<f64> = results.iter().map(|r| r.mb_per_s).collect();
30    let latencies: Vec<f64> = results.iter().map(|r| r.elapsed * 1000.0).collect();
31
32    let total_tests = results.len();
33
34    let avg_throughput = mean(&throughputs);
35    let min_throughput = throughputs
36        .iter()
37        .cloned()
38        .fold(f64::INFINITY, f64::min);
39    let max_throughput = throughputs
40        .iter()
41        .cloned()
42        .fold(f64::NEG_INFINITY, f64::max);
43
44    let avg_latency = mean(&latencies);
45    let stddev_latency = stddev_population(&latencies);
46
47    Summary {
48        total_tests,
49        avg_throughput_mb_s: avg_throughput,
50        min_throughput_mb_s: min_throughput,
51        max_throughput_mb_s: max_throughput,
52        avg_latency_ms: avg_latency,
53        stddev_latency_ms: stddev_latency,
54    }
55}
56
57/// Compute mean of a slice
58fn mean(values: &[f64]) -> f64 {
59    if values.is_empty() {
60        0.0
61    } else {
62        values.iter().sum::<f64>() / values.len() as f64
63    }
64}
65
66/// Population standard deviation
67fn stddev_population(values: &[f64]) -> f64 {
68    if values.is_empty() {
69        return 0.0;
70    }
71    let m = mean(values);
72    let variance = values.iter().map(|v| (v - m).powi(2)).sum::<f64>() / values.len() as f64;
73    variance.sqrt()
74}
75
76// ### 🧩 Key Notes
77// - `Summary` struct mirrors the Python dictionary return value.
78// - `mean` and `stddev_population` are helper functions to replicate `statistics.mean` and `statistics.pstdev`.
79// - Latency is converted to milliseconds (`elapsed * 1000.0`).
80// - Throughput stats (avg, min, max) are computed directly from the results.