Task 1 of 5
On a CPU a histogram is three lines. Make an array of zeros, walk the data, add one to the bin each value belongs to. It is the friendliest loop in programming.
const bins = new Array(16).fill(0);
for (let i = 0; i < data.length; i++) bins[data[i]]++;
Now run that loop on 4,096 threads at once. bins[v]++ is not one operation,
it is three — read bin v, add one,
write bin v back. Two threads whose values land in the same bin
both read 7, both compute 8, both write 8. Two increments went in; one came out. Nothing
crashed and nothing warned — a count is just quietly too low, and differently too low every
time you run it.
This is not a gpu.js quirk. It is precisely why CUDA ships atomicAdd: the
read-modify-write has to become indivisible, and making it indivisible means the colliding
threads take turns. gpu.js hands you no atomics and no scatter at all — a thread writes one
cell, its own — which forces the formulation that actually transfers: invert the
loop. Stop asking "which bin does my value go to?" and start asking "which values
belong to my bin?". Start with one bin.
codes equal this.constants.target.output: [1] — one thread, one bin, one countfor (let i = 0; i < this.constants.n; i++) over every codethis.constants.target — the value itself is not what a histogram countsThe count lives in a local let count = 0; that only this thread can
see. That is the whole reason there is nothing to race over: private variables cannot
collide.
if (codes[i] === this.constants.target) count++;atomicAdd, WGSL has atomicAdd on an
atomic<u32> in a storage buffer, Metal has
atomic_fetch_add_explicit. They are correct and they are not free: colliding
threads serialize, and a histogram with one hot bin can reduce a whole warp to single file.
The gather you are about to write is what the fast implementations fall back to when
contention gets bad enough — which is why it is worth knowing even where atomics exist.
This page is an interactive exercise — the editor, the GPU runner and your saved progress need JavaScript. The text above is the full brief.