809: Add overflow detection to hello-compute r=kvark a=danwilhelm

Description
The `hello-compute` example sometimes gives incorrect results if an intermediate Collatz value overflows. 

Proposed Solution
We can detect overflows before they occur, since the `3n+1` step is the only possible overflow. (WGSL only supports u32.)

Example
`cargo run --example hello-compute 77031 837799 8400511 63728127` 
> Incorrect Current Output: `[350, 524, 312, 346]`
> Correct Output: `[350, 524, 685, 949]`
> Proposed Solution: `[350, 524, OVERFLOW, OVERFLOW]`

Notes
- The `hello-compute` example appears to be [borrowed from naga](https://github.com/gfx-rs/naga/blob/master/tests/in/collatz.wgsl), so this would cause the implementations to differ.
- Hexadecimal literals are not yet implemented in naga for WGSL shaders, so the shader literals are not as pretty as they could be.
- Revised terminology `times` -> `steps` to be consistent with [Wikipedia](https://en.wikipedia.org/wiki/Collatz_conjecture).


Co-authored-by: Dan Wilhelm <dan@danwilhelm.com>
This commit is contained in:
bors[bot]
2021-03-23 14:32:47 +00:00
committed by GitHub
2 changed files with 29 additions and 3 deletions

View File

@@ -1,6 +1,9 @@
use std::{borrow::Cow, convert::TryInto, str::FromStr};
use wgpu::util::DeviceExt;
// Indicates a u32 overflow in an intermediate Collatz value
const OVERFLOW: u32 = 0xffffffff;
async fn run() {
let numbers = if std::env::args().len() <= 1 {
let default = vec![1, 2, 3, 4];
@@ -13,10 +16,19 @@ async fn run() {
.collect()
};
let times = execute_gpu(numbers).await;
println!("Times: {:?}", times);
let steps = execute_gpu(numbers).await;
let disp_steps: Vec<String> = steps
.iter()
.map(|&n| match n {
OVERFLOW => "OVERFLOW".to_string(),
_ => n.to_string(),
})
.collect();
println!("Steps: [{}]", disp_steps.join(", "));
#[cfg(target_arch = "wasm32")]
log::info!("Times: {:?}", times);
log::info!("Steps: [{}]", disp_steps.join(", "));
}
async fn execute_gpu(numbers: Vec<u32>) -> Vec<u32> {
@@ -194,6 +206,15 @@ mod tests {
pollster::block_on(assert_execute_gpu(input, vec![5, 15, 6, 19]));
}
#[test]
fn test_compute_overflow() {
let input = vec![77031, 837799, 8400511, 63728127];
pollster::block_on(assert_execute_gpu(
input,
vec![350, 524, OVERFLOW, OVERFLOW],
));
}
#[test]
fn test_multithreaded_compute() {
use std::{sync::mpsc, thread, time::Duration};

View File

@@ -23,6 +23,11 @@ fn collatz_iterations(n_base: u32) -> u32{
n = n / 2u;
}
else {
// Overflow? (i.e. 3*n + 1 > 0xffffffffu?)
if (n >= 1431655765u) { // 0x55555555u
return 4294967295u; // 0xffffffffu
}
n = 3u * n + 1u;
}
i = i + 1u;