dsfb_gpu_debug_demo/cli/
run_gpu.rs1use std::fs;
20use std::path::Path;
21use std::process::ExitCode;
22
23use dsfb_gpu_debug_core::bank::bank_hash;
24use dsfb_gpu_debug_core::casefile::emit;
25use dsfb_gpu_debug_core::contract::Contract;
26use dsfb_gpu_debug_core::motif::registry_hash;
27use dsfb_gpu_debug_core::serialize::read_fixture;
28use dsfb_gpu_debug_cuda::{build_gpu, GpuError};
29
30use super::{parse_flags, require_flag, usage_error};
31
32pub fn parse_and_run(args: &[String]) -> ExitCode {
33 let flags = match parse_flags(args) {
34 Ok(f) => f,
35 Err(message) => return usage_error(&message),
36 };
37 let fixture_path = match require_flag(&flags, "fixture") {
38 Ok(s) => s.to_string(),
39 Err(message) => return usage_error(&message),
40 };
41 let out_path = match require_flag(&flags, "out") {
42 Ok(s) => s.to_string(),
43 Err(message) => return usage_error(&message),
44 };
45 let _contract_path = flags.get("contract").cloned();
46
47 let raw = match fs::read(&fixture_path) {
48 Ok(bytes) => bytes,
49 Err(error) => {
50 eprintln!("dsfb-gpu-debug: failed to read {fixture_path}: {error}");
51 return ExitCode::from(5);
52 }
53 };
54 let events = match read_fixture(&raw) {
55 Ok(events) => events,
56 Err(error) => {
57 eprintln!("dsfb-gpu-debug: fixture parse error: {error:?}");
58 return ExitCode::from(5);
59 }
60 };
61
62 let mut contract = Contract::canonical();
63 contract.pin_bank_hash(bank_hash());
64 contract.pin_detector_registry_hash(registry_hash());
65
66 let case = match build_gpu(&events, &contract) {
67 Ok(case) => case,
68 Err(GpuError::CudaUnavailable) => {
69 eprintln!("dsfb-gpu-debug: GPU pipeline unavailable (built without --features cuda)");
70 return ExitCode::from(2);
71 }
72 Err(GpuError::KernelFailed(code)) => {
73 eprintln!("dsfb-gpu-debug: GPU kernel failed with cuda status {code}");
74 return ExitCode::from(2);
75 }
76 Err(GpuError::InvalidInput(msg)) => {
77 eprintln!("dsfb-gpu-debug: GPU dispatcher rejected input: {msg}");
78 return ExitCode::from(2);
79 }
80 };
81
82 let bytes = emit(&case);
83
84 if let Some(parent) = Path::new(&out_path).parent() {
85 if !parent.as_os_str().is_empty() {
86 if let Err(error) = fs::create_dir_all(parent) {
87 eprintln!(
88 "dsfb-gpu-debug: could not create {}: {error}",
89 parent.display()
90 );
91 return ExitCode::from(5);
92 }
93 }
94 }
95 if let Err(error) = fs::write(&out_path, &bytes) {
96 eprintln!("dsfb-gpu-debug: failed to write {out_path}: {error}");
97 return ExitCode::from(5);
98 }
99
100 eprintln!(
101 "dsfb-gpu-debug: wrote GPU case file ({} bytes, {} episodes, verdict={}) to {out_path}",
102 bytes.len(),
103 case.episodes.len(),
104 case.final_verdict.name(),
105 );
106 ExitCode::from(case.final_verdict.exit_code())
107}