Skip to main content

ruvector_profiler/
csv_emitter.rs

1use crate::latency::LatencyRecord;
2use crate::memory::MemorySnapshot;
3use std::io::Write;
4
5#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
6pub struct ResultRow {
7    pub setting: String,
8    pub coherence_delta: f64,
9    pub kv_cache_reduction: f64,
10    pub peak_mem_reduction: f64,
11    pub energy_reduction: f64,
12    pub p95_latency_us: u64,
13    pub accuracy: f64,
14}
15
16pub fn write_results_csv(path: &str, rows: &[ResultRow]) -> std::io::Result<()> {
17    let mut f = std::fs::File::create(path)?;
18    writeln!(f, "setting,coherence_delta,kv_cache_reduction,peak_mem_reduction,energy_reduction,p95_latency_us,accuracy")?;
19    for r in rows {
20        writeln!(f, "{},{},{},{},{},{},{}", esc(&r.setting),
21            r.coherence_delta, r.kv_cache_reduction, r.peak_mem_reduction,
22            r.energy_reduction, r.p95_latency_us, r.accuracy)?;
23    }
24    Ok(())
25}
26
27pub fn write_latency_csv(path: &str, records: &[LatencyRecord]) -> std::io::Result<()> {
28    let mut f = std::fs::File::create(path)?;
29    writeln!(f, "sample_id,wall_time_us,kernel_time_us,seq_len")?;
30    for r in records {
31        writeln!(f, "{},{},{},{}", r.sample_id, r.wall_time_us, r.kernel_time_us, r.seq_len)?;
32    }
33    Ok(())
34}
35
36pub fn write_memory_csv(path: &str, snapshots: &[MemorySnapshot]) -> std::io::Result<()> {
37    let mut f = std::fs::File::create(path)?;
38    writeln!(f, "timestamp_us,peak_rss_bytes,kv_cache_bytes,activation_bytes,temp_buffer_bytes")?;
39    for s in snapshots {
40        writeln!(f, "{},{},{},{},{}", s.timestamp_us, s.peak_rss_bytes,
41            s.kv_cache_bytes, s.activation_bytes, s.temp_buffer_bytes)?;
42    }
43    Ok(())
44}
45
46fn esc(s: &str) -> String {
47    if s.contains(',') || s.contains('"') || s.contains('\n') {
48        format!("\"{}\"", s.replace('"', "\"\""))
49    } else { s.to_string() }
50}
51
52#[cfg(test)]
53mod tests {
54    use super::*;
55
56    #[test] fn esc_plain() { assert_eq!(esc("hello"), "hello"); }
57    #[test] fn esc_comma() { assert_eq!(esc("a,b"), "\"a,b\""); }
58
59    #[test]
60    fn roundtrip_results() {
61        let d = tempfile::tempdir().unwrap();
62        let p = d.path().join("r.csv");
63        write_results_csv(p.to_str().unwrap(), &[ResultRow {
64            setting: "base".into(), coherence_delta: 0.01, kv_cache_reduction: 0.0,
65            peak_mem_reduction: 0.0, energy_reduction: 0.0, p95_latency_us: 1200, accuracy: 0.95,
66        }]).unwrap();
67        let c = std::fs::read_to_string(&p).unwrap();
68        assert_eq!(c.lines().count(), 2);
69    }
70
71    #[test]
72    fn roundtrip_latency() {
73        let d = tempfile::tempdir().unwrap();
74        let p = d.path().join("l.csv");
75        write_latency_csv(p.to_str().unwrap(), &[
76            LatencyRecord { sample_id: 0, wall_time_us: 100, kernel_time_us: 80, seq_len: 64 },
77        ]).unwrap();
78        assert_eq!(std::fs::read_to_string(&p).unwrap().lines().count(), 2);
79    }
80
81    #[test]
82    fn roundtrip_memory() {
83        let d = tempfile::tempdir().unwrap();
84        let p = d.path().join("m.csv");
85        write_memory_csv(p.to_str().unwrap(), &[MemorySnapshot {
86            peak_rss_bytes: 1024, kv_cache_bytes: 256, activation_bytes: 512,
87            temp_buffer_bytes: 128, timestamp_us: 999,
88        }]).unwrap();
89        let c = std::fs::read_to_string(&p).unwrap();
90        assert!(c.contains("999,1024,256,512,128"));
91    }
92}