Task 1 of 6
A prefix sum — a scan — is a running total. Give it
[3, 1, 4, 1] and it answers [3, 4, 8, 9]: cell i
holds everything from the start up to and including element i. A reduction
collapses an array to a single number; a scan keeps every partial answer along
the way, which turns out to be far more useful.
In JavaScript it is two lines, and the shape of those two lines is the whole problem:
out[0] = x[0];
out[i] = out[i - 1] + x[i];
Look at what cell i needs: not its neighbour's input, but its
neighbour's answer. Every thread on a GPU starts at the same instant, so
when thread 7 reaches for out[6] nobody has computed it yet — and nobody will,
because thread 6 is waiting on thread 5. That is a serial dependency chain as long as the
array, and it cannot be a kernel. Write it here in plain JavaScript first; the rest of
this module is five ways around it.
running so that running[i] is
the total rainfall of days 0 … i, then log the array and the season total.running[0] is just rainfall[0]; every later cell adds that day to the cell before itconsole.log the whole running array, and the season totalCell 0 has nothing before it, so it is the only cell that does not read
running[i - 1]. Set it first, then loop from i = 1.
running[0] = rainfall[0];
for (let i = 1; i < rainfall.length; i++) {
running[i] = running[i - 1] + rainfall[i];
}
The season total is the last cell — an inclusive scan ends with the reduction already done.
thrust::inclusive_scan and CUB's
DeviceScan, ROCm has rocPRIM's inclusive_scan, Metal Shading
Language has simd_prefix_inclusive_sum, and WGSL's subgroup extension has
subgroupInclusiveAdd. All of them exist to break the chain you are about to
feel.
This page is an interactive exercise — the editor, the GPU runner and your saved progress need JavaScript. The text above is the full brief.