/ concept-collection / turing-surface
Sign in
concept-collection / turing-surface
Scale the randnfun3 GPU/CPU bound to the field
The check sums ~1400 Fourier modes in fp32 on the device and compares against the same table summed in f64, against an absolute 2e-6. That constant was read off desktop Metal, which lands at 1.98e-6 -- one percent of margin on a quantity whose size is the backend's accumulation order. SwiftShader accumulates differently and lands at 3.77e-6, so CI's software adapter fails a kernel that is doing nothing wrong. Neither number is improvable: Dawn folds a Kahan compensation away, and this floor is summation-limited. Bound it by the field instead, at 1e-3 of the perturbation amplitude -- 2.9e-5 at the default wavelength, eight times SwiftShader's measurement. The check loses no power, because what it is built to catch is a mis-indexed read into the packed mode table, which yields a field that still looks smooth and random but is wrong by O(amp), a thousand times over the new bound. This never passed in CI. Every run died earlier, at numbl's missing stdlib bundle, so the browser suite had not reached it since randnfun3 landed. Verified on both backends: SwiftShader reproduces 3.77e-6 locally and the suite passes; desktop Dawn stays at 1.98e-6.
Dan Fortunato <dan.fortunato@gmail.com> committed commit c2fcb487a9b7 parent cc9b1ca Browse files
1 changed file+8−2
test/geometryChecks.tsmodified+8−2View file
@@ -593,8 +593,14 @@ async function randnfun3Checks(
593593 log(` randnfun3: ${nmodes} modes at lambda ${DEFAULT_LAMBDA}, |perturbation| up to ${amp.toExponential(2)}`);
594594 check(
595595 'randnfun3: the GPU sum matches the same modes summed on the CPU',
596- // fp32 over ~1400 terms against f64, on a field of amplitude ~1e-2.
597- maxErr < 2e-6 && amp > 1e-3,
596+ // fp32 over ~1400 terms against f64. What is being bounded is the
597+ // summation floor, and its size is the backend's accumulation order:
598+ // Metal lands at 2.0e-6, SwiftShader at 3.8e-6, so an absolute constant
599+ // tuned on one is a coin flip on the other. Scale it to the field
600+ // instead. The bug this exists to catch -- a mis-indexed read into the
601+ // packed table, which would still look like a smooth random field -- is
602+ // wrong by O(amp), a thousand times over the bound.
603+ maxErr < 1e-3 * amp && amp > 1e-3,
598604 `max |GPU - CPU| = ${maxErr.toExponential(2)}, perturbation amplitude ${amp.toExponential(2)}`,
599605 );
600606 session.destroy();
moveopenescclose