dsfb_gpu_debug_demo/cli/
compare.rs1use std::fs;
12use std::path::Path;
13use std::process::ExitCode;
14
15use dsfb_gpu_debug_core::serialize::{write_key, write_str, write_u64};
16use dsfb_gpu_debug_core::verdict::FinalVerdict;
17
18use super::{parse_flags, require_flag, usage_error};
19
20pub fn parse_and_run(args: &[String]) -> ExitCode {
21 let flags = match parse_flags(args) {
22 Ok(f) => f,
23 Err(message) => return usage_error(&message),
24 };
25 let cpu_path = match require_flag(&flags, "cpu") {
26 Ok(s) => s.to_string(),
27 Err(message) => return usage_error(&message),
28 };
29 let gpu_path = match require_flag(&flags, "gpu") {
30 Ok(s) => s.to_string(),
31 Err(message) => return usage_error(&message),
32 };
33 let out_path = match require_flag(&flags, "out") {
34 Ok(s) => s.to_string(),
35 Err(message) => return usage_error(&message),
36 };
37
38 let cpu_bytes = match fs::read(&cpu_path) {
39 Ok(b) => b,
40 Err(error) => {
41 eprintln!("dsfb-gpu-debug: failed to read {cpu_path}: {error}");
42 return ExitCode::from(5);
43 }
44 };
45 let gpu_bytes = match fs::read(&gpu_path) {
46 Ok(b) => b,
47 Err(error) => {
48 eprintln!("dsfb-gpu-debug: failed to read {gpu_path}: {error}");
49 return ExitCode::from(5);
50 }
51 };
52
53 let verdict = if cpu_bytes == gpu_bytes {
59 FinalVerdict::ReplayAdmissible
60 } else {
61 FinalVerdict::NumericMismatch
67 };
68
69 let report = write_comparison_report(
70 &cpu_path,
71 &gpu_path,
72 verdict,
73 cpu_bytes.len(),
74 gpu_bytes.len(),
75 );
76
77 if let Some(parent) = Path::new(&out_path).parent() {
78 if !parent.as_os_str().is_empty() {
79 if let Err(error) = fs::create_dir_all(parent) {
80 eprintln!(
81 "dsfb-gpu-debug: could not create {}: {error}",
82 parent.display()
83 );
84 return ExitCode::from(5);
85 }
86 }
87 }
88 if let Err(error) = fs::write(&out_path, &report) {
89 eprintln!("dsfb-gpu-debug: failed to write {out_path}: {error}");
90 return ExitCode::from(5);
91 }
92
93 eprintln!(
94 "dsfb-gpu-debug: comparison verdict={} (cpu={} bytes, gpu={} bytes)",
95 verdict.name(),
96 cpu_bytes.len(),
97 gpu_bytes.len()
98 );
99 ExitCode::from(verdict.exit_code())
100}
101
102fn write_comparison_report(
103 cpu_path: &str,
104 gpu_path: &str,
105 verdict: FinalVerdict,
106 cpu_len: usize,
107 gpu_len: usize,
108) -> Vec<u8> {
109 let mut buf: Vec<u8> = Vec::new();
110 buf.push(b'{');
111 write_key(&mut buf, "cpu_bytes");
112 write_u64(&mut buf, cpu_len as u64);
113 buf.push(b',');
114 write_key(&mut buf, "cpu_path");
115 write_str(&mut buf, cpu_path);
116 buf.push(b',');
117 write_key(&mut buf, "gpu_bytes");
118 write_u64(&mut buf, gpu_len as u64);
119 buf.push(b',');
120 write_key(&mut buf, "gpu_path");
121 write_str(&mut buf, gpu_path);
122 buf.push(b',');
123 write_key(&mut buf, "verdict");
124 write_str(&mut buf, verdict.name());
125 buf.push(b'}');
126 buf
127}