ellip_dev_utils/
benchmark.rs

1/*
2 * Ellip is licensed under The 3-Clause BSD, see LICENSE.
3 * Copyright 2025 Sira Pornsiriprasert <code@psira.me>
4 */
5
6use std::path::PathBuf;
7
8use crate::StrErr;
9
10/// Criterion benchmark estimates structure
11#[derive(Debug, serde::Deserialize)]
12pub struct CriterionEstimates {
13    pub mean: CriterionMean,
14}
15
16/// Criterion mean structure
17#[derive(Debug, serde::Deserialize)]
18pub struct CriterionMean {
19    pub point_estimate: f64,
20}
21
22pub fn extract_criterion_mean(path: &PathBuf) -> Result<f64, StrErr> {
23    use std::fs;
24    let content = fs::read_to_string(path).map_err(|_| "Cannot read estimates.json file")?;
25
26    let estimates: CriterionEstimates =
27        serde_json::from_str(&content).map_err(|_| "Cannot parse estimates.json file")?;
28
29    Ok(estimates.mean.point_estimate)
30}
31
32pub fn extract_criterion_means(paths: &[PathBuf]) -> Result<Vec<f64>, StrErr> {
33    paths
34        .iter()
35        .map(|path| extract_criterion_mean(path))
36        .collect()
37}
38
39#[cfg(test)]
40mod tests {
41    use super::*;
42    use std::fs;
43    use tempfile::tempdir;
44
45    #[test]
46    fn test_extract_criterion_mean() {
47        // Create a temporary directory with a mock estimates.json
48        let temp_dir = tempdir().unwrap();
49        let estimates_content = r#"{
50            "mean": {
51                "confidence_interval": {
52                    "confidence_level": 0.95,
53                    "lower_bound": 100.0,
54                    "upper_bound": 200.0
55                },
56                "point_estimate": 150.5,
57                "standard_error": 25.0
58            }
59        }"#;
60
61        let estimates_path = temp_dir.path().join("estimates.json");
62        fs::write(&estimates_path, estimates_content).unwrap();
63
64        let mean = extract_criterion_mean(&estimates_path).unwrap();
65        assert_eq!(mean, 150.5);
66    }
67
68    #[test]
69    fn test_extract_criterion_means() {
70        // Create temporary directories with mock estimates.json files
71        let temp_dir1 = tempdir().unwrap();
72        let temp_dir2 = tempdir().unwrap();
73
74        let estimates_content1 = r#"{"mean":{"point_estimate":100.0}}"#;
75        let estimates_content2 = r#"{"mean":{"point_estimate":200.0}}"#;
76
77        let paths = vec![
78            temp_dir1.path().join("estimates.json"),
79            temp_dir2.path().join("estimates.json"),
80        ];
81
82        fs::write(paths[0].clone(), estimates_content1).unwrap();
83        fs::write(paths[1].clone(), estimates_content2).unwrap();
84
85        let means = extract_criterion_means(&paths).unwrap();
86        assert_eq!(means, vec![100.0, 200.0]);
87    }
88}