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}