Skip to main content

cgp/metrics/
export.rs

1//! JSON export for profile data. Spec section 10.
2
3use super::catalog::FullProfile;
4use anyhow::Result;
5use std::path::Path;
6
7/// Export a profile to JSON file.
8pub fn export_json(profile: &FullProfile, path: &Path) -> Result<()> {
9    let json = serde_json::to_string_pretty(profile)?;
10    std::fs::write(path, json)?;
11    Ok(())
12}
13
14/// Load a profile from JSON file.
15pub fn load_json(path: &Path) -> Result<FullProfile> {
16    let content = std::fs::read_to_string(path)?;
17    let profile: FullProfile = serde_json::from_str(&content)?;
18    Ok(profile)
19}
20
21#[cfg(test)]
22mod tests {
23    use super::*;
24    use crate::metrics::catalog::{ThroughputMetrics, TimingMetrics};
25
26    #[test]
27    fn test_export_load_roundtrip() {
28        let profile = FullProfile {
29            version: "2.0".to_string(),
30            timestamp: "2026-04-04T12:00:00Z".to_string(),
31            timing: TimingMetrics {
32                wall_clock_time_us: 23.2,
33                samples: 50,
34                ..Default::default()
35            },
36            throughput: ThroughputMetrics {
37                tflops: 11.6,
38                ..Default::default()
39            },
40            ..Default::default()
41        };
42
43        let dir = tempfile::tempdir().unwrap();
44        let path = dir.path().join("test_profile.json");
45        export_json(&profile, &path).unwrap();
46        let loaded = load_json(&path).unwrap();
47        assert_eq!(loaded.version, "2.0");
48        assert!((loaded.timing.wall_clock_time_us - 23.2).abs() < 0.01);
49    }
50
51    /// FALSIFY-CGP-062: diff must not require re-profiling.
52    /// Loading two saved JSONs should be < 100ms.
53    #[test]
54    fn test_json_load_speed() {
55        let profile = FullProfile {
56            version: "2.0".to_string(),
57            ..Default::default()
58        };
59        let dir = tempfile::tempdir().unwrap();
60        let path = dir.path().join("speed_test.json");
61        export_json(&profile, &path).unwrap();
62
63        let start = std::time::Instant::now();
64        let _ = load_json(&path).unwrap();
65        let _ = load_json(&path).unwrap();
66        let elapsed = start.elapsed();
67        assert!(
68            elapsed.as_millis() < 100,
69            "Loading two JSONs took {}ms (should be <100ms)",
70            elapsed.as_millis()
71        );
72    }
73}