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!(
21 f,
22 "{},{},{},{},{},{},{}",
23 esc(&r.setting),
24 r.coherence_delta,
25 r.kv_cache_reduction,
26 r.peak_mem_reduction,
27 r.energy_reduction,
28 r.p95_latency_us,
29 r.accuracy
30 )?;
31 }
32 Ok(())
33}
34
35pub fn write_latency_csv(path: &str, records: &[LatencyRecord]) -> std::io::Result<()> {
36 let mut f = std::fs::File::create(path)?;
37 writeln!(f, "sample_id,wall_time_us,kernel_time_us,seq_len")?;
38 for r in records {
39 writeln!(
40 f,
41 "{},{},{},{}",
42 r.sample_id, r.wall_time_us, r.kernel_time_us, r.seq_len
43 )?;
44 }
45 Ok(())
46}
47
48pub fn write_memory_csv(path: &str, snapshots: &[MemorySnapshot]) -> std::io::Result<()> {
49 let mut f = std::fs::File::create(path)?;
50 writeln!(
51 f,
52 "timestamp_us,peak_rss_bytes,kv_cache_bytes,activation_bytes,temp_buffer_bytes"
53 )?;
54 for s in snapshots {
55 writeln!(
56 f,
57 "{},{},{},{},{}",
58 s.timestamp_us,
59 s.peak_rss_bytes,
60 s.kv_cache_bytes,
61 s.activation_bytes,
62 s.temp_buffer_bytes
63 )?;
64 }
65 Ok(())
66}
67
68fn esc(s: &str) -> String {
69 if s.contains(',') || s.contains('"') || s.contains('\n') {
70 format!("\"{}\"", s.replace('"', "\"\""))
71 } else {
72 s.to_string()
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79
80 #[test]
81 fn esc_plain() {
82 assert_eq!(esc("hello"), "hello");
83 }
84 #[test]
85 fn esc_comma() {
86 assert_eq!(esc("a,b"), "\"a,b\"");
87 }
88
89 #[test]
90 fn roundtrip_results() {
91 let d = tempfile::tempdir().unwrap();
92 let p = d.path().join("r.csv");
93 write_results_csv(
94 p.to_str().unwrap(),
95 &[ResultRow {
96 setting: "base".into(),
97 coherence_delta: 0.01,
98 kv_cache_reduction: 0.0,
99 peak_mem_reduction: 0.0,
100 energy_reduction: 0.0,
101 p95_latency_us: 1200,
102 accuracy: 0.95,
103 }],
104 )
105 .unwrap();
106 let c = std::fs::read_to_string(&p).unwrap();
107 assert_eq!(c.lines().count(), 2);
108 }
109
110 #[test]
111 fn roundtrip_latency() {
112 let d = tempfile::tempdir().unwrap();
113 let p = d.path().join("l.csv");
114 write_latency_csv(
115 p.to_str().unwrap(),
116 &[LatencyRecord {
117 sample_id: 0,
118 wall_time_us: 100,
119 kernel_time_us: 80,
120 seq_len: 64,
121 }],
122 )
123 .unwrap();
124 assert_eq!(std::fs::read_to_string(&p).unwrap().lines().count(), 2);
125 }
126
127 #[test]
128 fn roundtrip_memory() {
129 let d = tempfile::tempdir().unwrap();
130 let p = d.path().join("m.csv");
131 write_memory_csv(
132 p.to_str().unwrap(),
133 &[MemorySnapshot {
134 peak_rss_bytes: 1024,
135 kv_cache_bytes: 256,
136 activation_bytes: 512,
137 temp_buffer_bytes: 128,
138 timestamp_us: 999,
139 }],
140 )
141 .unwrap();
142 let c = std::fs::read_to_string(&p).unwrap();
143 assert!(c.contains("999,1024,256,512,128"));
144 }
145}