1use cram_codec::codec::ErrorBound;
9use cram_codec::gpuwav3::{self, Gpu3Config, Model3};
10
11fn opt(args: &[String], k: &str, d: &str) -> String {
12 args.iter()
13 .position(|a| a == k)
14 .map(|i| args[i + 1].clone())
15 .unwrap_or_else(|| d.to_string())
16}
17
18const ORIG: [&str; 5] = [
19 "miranda-density",
20 "miranda-velocityx",
21 "hurricane-TC",
22 "hurricane-U",
23 "nyx-temperature",
24];
25
26fn main() {
27 let args: Vec<String> = std::env::args().skip(1).collect();
28 let root = std::path::PathBuf::from(&args[0]);
29 let threads: usize = opt(&args, "--threads", "16").parse().unwrap();
30 let lanes: usize = opt(&args, "--l3", "8").parse().unwrap();
31 let m = opt(&args, "--model3", "static");
32 let model = if m == "static" {
33 Model3::Static
34 } else if let Some(p) = m.strip_prefix("pretrained:") {
35 let net = std::sync::Arc::new(
36 cram_codec::learned::Net::from_bytes(&std::fs::read(p).expect("model")).expect("parse"),
37 );
38 cram_codec::learned::register(net.clone());
39 Model3::Pretrained(net)
40 } else {
41 panic!("model3 {m}")
42 };
43 let mut fields: Vec<(String, std::path::PathBuf, Vec<usize>)> = ORIG
44 .iter()
45 .map(|n| {
46 (
47 n.to_string(),
48 root.join(format!("out/{n}-64x128x128.f32")),
49 vec![64, 128, 128],
50 )
51 })
52 .collect();
53 let man = std::fs::read_to_string(root.join("data/heldout/manifest.json")).unwrap();
54 for obj in man.split('{').skip(1) {
56 let name = obj
57 .split("\"name\"")
58 .nth(1)
59 .unwrap()
60 .split('"')
61 .nth(1)
62 .unwrap()
63 .to_string();
64 let sh = obj
65 .split("\"shape\"")
66 .nth(1)
67 .unwrap()
68 .split('[')
69 .nth(1)
70 .unwrap()
71 .split(']')
72 .next()
73 .unwrap();
74 let shape: Vec<usize> = sh.split(',').map(|v| v.trim().parse().unwrap()).collect();
75 fields.push((
76 name.clone(),
77 root.join(format!("data/heldout/{name}.f32")),
78 shape,
79 ));
80 }
81 let only = opt(&args, "--only", "");
82 let ser: std::collections::HashMap<(String, String), f64> =
83 std::fs::read_to_string(root.join("out/gpu_ratio.jsonl"))
84 .unwrap()
85 .lines()
86 .filter(|l| l.contains("\"tc-wavelet\""))
87 .map(|l| {
88 let g = |k: &str| {
89 l.split(&format!("\"{k}\":"))
90 .nth(1)
91 .unwrap()
92 .split([',', '}'])
93 .next()
94 .unwrap()
95 .trim()
96 .trim_matches('"')
97 .to_string()
98 };
99 (
100 (g("field").replace("-64x128x128", ""), g("target")),
101 g("bpv").parse().unwrap(),
102 )
103 })
104 .collect();
105 let mut acc: std::collections::HashMap<(String, String), Vec<f64>> = Default::default();
106 for t in opt(&args, "--targets", "p80").split(',') {
107 for (name, path, dims) in &fields {
108 if !only.is_empty() && !only.split(',').any(|o| name.contains(o)) {
109 continue;
110 }
111 let b = std::fs::read(path).unwrap();
112 let x: Vec<f32> = b
113 .as_chunks::<4>()
114 .0
115 .iter()
116 .map(|&c| f32::from_le_bytes(c))
117 .collect();
118 let range = x.iter().fold(f32::NEG_INFINITY, |a, &b| a.max(b)) as f64
119 - x.iter().fold(f32::INFINITY, |a, &b| a.min(b)) as f64;
120 let bound = if let Some(p) = t.strip_prefix('p') {
121 ErrorBound::Psnr(p.parse().unwrap())
122 } else {
123 ErrorBound::MaxAbs(t[1..].parse::<f64>().unwrap() * range)
124 };
125 let cfg = Gpu3Config {
126 lanes,
127 compact: !args.iter().any(|a| a == "--nocompact"),
128 axis: !args.iter().any(|a| a == "--noaxis"),
129 model: model.clone(),
130 ..Gpu3Config::new(bound)
131 };
132 let (s, _) = gpuwav3::encode3_f32(&x, dims, &cfg, threads);
133 let bpv = s.len() as f64 * 8.0 / x.len() as f64;
134 let r = ser.get(&(name.clone(), t.to_string())).map(|sb| bpv / sb);
135 println!(
136 "{{\"field\": \"{name}\", \"target\": \"{t}\", \"bpv\": {bpv}, \"vs_serial\": {}}}",
137 r.map_or("null".into(), |v| format!("{v:.4}"))
138 );
139 if let Some(r) = r {
140 let g = if ORIG.contains(&name.as_str()) {
141 "orig"
142 } else {
143 "held"
144 };
145 acc.entry((t.to_string(), "all".into()))
146 .or_default()
147 .push(r);
148 acc.entry((t.to_string(), g.into())).or_default().push(r);
149 }
150 }
151 }
152 let mut keys: Vec<_> = acc.keys().cloned().collect();
153 keys.sort();
154 for k in keys {
155 let v = &acc[&k];
156 let gm = (v.iter().map(|x| x.ln()).sum::<f64>() / v.len() as f64).exp();
157 println!("GEOMEAN {} {} n={} {:.4}", k.0, k.1, v.len(), gm);
158 }
159}