parallel prefix scan

**Parallel Prefix Sum (Scan)** is the **fundamental parallel computing primitive that computes all prefix sums of an input array — where prefix_sum[i] = sum(input[0..i]) for all i simultaneously — in O(N/P + log P) time on P processors, serving as the building block for parallel sorting, stream compaction, histogram computation, and virtually every parallel algorithm that requires computing cumulative quantities or assigning output positions dynamically**. **Why Scan Is Foundational** Sequentially, computing prefix sums is trivial: iterate once, accumulating. But in parallel, each element's result depends on all preceding elements — a seemingly inherently serial dependency chain. The breakthrough is that associative operations can be restructured into a tree pattern that computes all prefixes in O(log N) parallel steps. **Scan Variants** - **Exclusive Scan**: output[i] = sum(input[0..i-1]). output[0] = 0 (identity element). Used for computing output positions (scatter addresses). - **Inclusive Scan**: output[i] = sum(input[0..i]). Each element includes itself. - **Segmented Scan**: Scan that resets at segment boundaries. Enables parallel processing of variable-length sequences (e.g., per-row operations in sparse matrices). **Blelloch's Work-Efficient Parallel Scan** Two phases on a balanced binary tree: 1. **Up-Sweep (Reduce)**: Bottom-up, each node stores the sum of its left and right children. After log₂(N) steps, the root contains the total sum. Total work: N-1 additions. 2. **Down-Sweep**: Top-down, the root receives 0 (identity). Each node passes its value to its left child and (its value + left child's old value) to its right child. After log₂(N) steps, every leaf contains its exclusive prefix sum. Total work: N-1 additions. Total work: 2(N-1) additions — the same as sequential (work-efficient). Span: 2×log₂(N) steps. **GPU Implementation** - **Block-Level Scan**: Each thread block loads a tile (512-2048 elements) into shared memory and performs the up-sweep/down-sweep within the block using __syncthreads() barriers. - **Grid-Level Scan**: For arrays larger than one block's capacity, a three-kernel approach: (1) block-level scan producing per-block partial sums, (2) scan of the partial sums, (3) add each block's prefix to all elements in that block. - **Warp-Level Scan**: For the last 32 elements, use __shfl_up_sync() to perform prefix sum within a warp without shared memory or barriers — the fastest possible implementation. **Critical Applications** - **Stream Compaction**: Given an array and a predicate, extract elements that satisfy the predicate into a dense output array. Scan of the predicate flags computes the output position for each surviving element. - **Radix Sort**: Each pass of parallel radix sort uses scan to compute the destination index for each element based on its digit value. - **Sparse Matrix Construction**: Scan of row nonzero counts computes the row pointer array (CSR format) for a sparse matrix. - **Histogram**: Scan of bin counts computes cumulative histogram (used in histogram equalization and percentile computation). Parallel Scan is **the universal addressing primitive of parallel computing** — the algorithm that answers "where does each element go?" in parallel, enabling the dynamic data movement that makes complex parallel algorithms possible on architectures with no shared mutable state.

Go deeper with CFSGPT

Get AI-powered deep-dives, save terms, and run advanced simulations — free account.

Create Free Account