//! One device shared by many threads, as a pack that codes many pieces at once shares //! it: every call of every thread completes on the device (none is handed back to the //! CPU) and gives the reference's result. A call whose buffer map is completed by another //! thread's poll is the case this holds: the wait is for the map, not only for the //! submission. mod support; use support::*; #[test] fn every_call_completes_under_many_threads() { for g in gpus() { let (h, w, block, range, prec) = (24usize, 40usize, 8usize, 3i64, 2i64); let mut rng = Rng(0x5eed_0004); let pairs: Vec<(Vec, Vec)> = (0..8).map(|_| (rng.bytes(h * w * 3), rng.bytes(h * w * 3))).collect(); let want: Vec> = pairs.iter().map(|(s, r)| search(s, r, h, w, block, range, prec)).collect(); let msgs: Vec> = (0..8).map(|i| rng.bytes(1000 + 997 * i)).collect(); let failures = std::sync::atomic::AtomicU64::new(0); std::thread::scope(|s| { for t in 0..16 { let (g, pairs, want, msgs, failures) = (&g, &pairs, &want, &msgs, &failures); s.spawn(move || { for i in 0..600 { let k = (t + i) % pairs.len(); let ok = if i % 3 == 0 { let m: Vec<&[u8]> = vec![msgs[k].as_slice()]; g.blake3_many(&m).map(|h| &h[0] == blake3::hash(&msgs[k]).as_bytes()) } else { g.motion_frame(&pairs[k].0, &pairs[k].1, h, w, block, range, prec).map(|v| v == want[k]) }; match ok { Ok(true) => {} Ok(false) => panic!("{}: thread {t} call {i}: a result other than the reference's", g.adapter().label()), Err(_) => { failures.fetch_add(1, std::sync::atomic::Ordering::Relaxed); } } } }); } }); let n = failures.load(std::sync::atomic::Ordering::Relaxed); assert_eq!(n, 0, "{}: {n} of 9,600 calls did not complete on the device", g.adapter().label()); eprintln!("{}: 16 threads, 9,600 calls, every one completed with the reference's result", g.adapter().label()); } }