//! The kernels' arithmetic on the device (`wgsl/arith.wgsl`): every 64-bit and 128-bit //! function, from 32-bit words, against the host's 128-bit integers, on the edges of //! every width pairwise, every shift under every rounding mode, and a million SplitMix64 //! cases, on every adapter found. Then an edit of one function (a carry dropped from the //! 32 × 32-bit product) is shown to be caught: discovery refuses the adapter. use std::io::Write; use wai_ops_gpu::probe::{self, ProbeIn}; use wai_ops_gpu::{blocking, kernels::Sources}; /// A result line, also appended to `WAI_OPS_GPU_REPORT` when it is set. fn report(line: &str) { println!("{line}"); if let Ok(p) = std::env::var("WAI_OPS_GPU_REPORT") { let mut f = std::fs::OpenOptions::new().create(true).append(true).open(&p).unwrap(); writeln!(f, "{line}").unwrap(); } } #[test] fn the_arithmetic_is_the_hosts_on_every_adapter() { let d = blocking::discover(); if d.found.is_empty() { println!("ops-gpu arith: SKIPPED: no adapter: {:?}", d.refused.iter().map(|(a, w)| (a.key(), w.clone())).collect::>()); assert!(std::env::var_os("WAI_OPS_GPU_REQUIRE").is_none(), "WAI_OPS_GPU_REQUIRE is set and no adapter was found"); return; } let mut cases: Vec = probe::cases(0, 0); for seed in 0..16u64 { let c = probe::cases(65536, 0xA417_0000 + seed); cases.extend_from_slice(&c[c.len() - 65536..]); } for g in &d.found { let mut checked = 0usize; for chunk in cases.chunks(1 << 16) { let got = blocking::probe(g, chunk).unwrap_or_else(|e| panic!("{}: {e}", g.adapter().key())); assert_eq!(probe::first_mismatch(chunk, &got), None, "{}", g.adapter().key()); checked += chunk.len(); } report(&format!("ops-gpu arith: key={} {} cases={checked} words={} equal", g.adapter().key(), g.adapter().describe(), checked * probe::OUT_WORDS)); } } #[test] fn an_edited_product_is_caught_by_the_probe() { let d = blocking::discover(); if d.found.is_empty() { println!("ops-gpu arith mutant: SKIPPED: no adapter"); assert!(std::env::var_os("WAI_OPS_GPU_REQUIRE").is_none(), "WAI_OPS_GPU_REQUIRE is set and no adapter was found"); return; } let mut src = Sources::shipped(); let from = "let hi = p11 + (mid2 >> 16u) + ((c1 + c2) << 16u);"; assert!(src.probe.contains(from)); src.probe = src.probe.replace(from, "let hi = p11 + (mid2 >> 16u) + (c2 << 16u);"); let m = blocking::discover_with(&src, "mutant: a carry dropped"); assert!(m.found.is_empty(), "an adapter passed the probe with a carry dropped"); for (a, why) in &m.refused { assert!(why.contains("probe"), "{}: refused for another reason: {why}", a.key()); println!("ops-gpu arith mutant: key={} refused: {why}", a.key()); } assert_eq!(m.refused.len(), d.found.len() + d.refused.len()); }