parallel prefix sum scan

**Parallel Prefix Sum (Scan)** is **a fundamental parallel primitive that computes all prefix sums (running totals) of an array in O(n/P + log n) parallel time, transforming an apparently sequential computation into a highly parallel one** — scan is arguably the most important building block in parallel algorithms, appearing in sorting, stream compaction, histogram computation, and memory allocation. **Scan Definitions:** - **Exclusive Scan**: output[i] = sum(input[0..i-1]), with output[0] = identity element (0 for addition) — the output at position i excludes the input at position i - **Inclusive Scan**: output[i] = sum(input[0..i]), including the input at position i — equivalent to exclusive scan shifted left by one position with the total sum appended - **Generalization**: scan works with any associative binary operator (addition, multiplication, max, min, bitwise OR/AND) — the operator doesn't need to be commutative, just associative - **Sequential Complexity**: O(n) trivially computed with a single loop — the challenge is computing it in O(log n) parallel steps while keeping total work close to O(n) **Hillis-Steele Algorithm (Inclusive Scan):** - **Algorithm**: in step d (d = 0, 1, ..., log₂(n)-1), each element i computes x[i] = x[i] + x[i - 2^d] if i ≥ 2^d — after log₂(n) steps, all prefix sums are computed - **Work**: O(n log n) total operations — not work-efficient (performs more operations than sequential O(n) scan) - **Span**: O(log n) parallel steps — good for hardware implementations where excess work doesn't matter (e.g., fixed-function circuits) - **GPU Implementation**: simple to implement with alternating buffers — each step requires a full array pass, making it straightforward but wasteful for large arrays **Blelloch Algorithm (Work-Efficient Scan):** - **Up-Sweep (Reduce)**: builds a binary tree of partial sums bottom-up in log₂(n) steps — step d computes x[k×2^(d+1) - 1] += x[k×2^(d+1) - 2^d - 1] for all valid k - **Down-Sweep (Distribute)**: traverses the tree top-down in log₂(n) steps — replaces each node with the prefix sum up to that point using saved intermediate values - **Work**: O(n) total operations — matches sequential scan, making it work-efficient - **Span**: O(log n) parallel steps — same depth as Hillis-Steele but with O(n) work instead of O(n log n) **GPU Implementation (CUDA):** - **Block-Level Scan**: each thread block scans a tile of data (typically 1024-2048 elements) in shared memory using Blelloch's algorithm — shared memory enables fast intra-block communication - **Block-Level Reduction**: the last element of each block's scan (the block total) is written to an auxiliary array — this array is itself scanned to compute inter-block offsets - **Block-Level Update**: each block adds its inter-block offset to all elements — this three-phase approach (scan, scan of block sums, update) achieves O(n/P + log n) time - **Performance**: CUB and Thrust library implementations achieve 80-90% of peak memory bandwidth on modern GPUs — for 100M elements, scan completes in <1 ms on an A100 **Scan Applications:** - **Stream Compaction**: given a predicate, pack matching elements into a contiguous array — compute a scan of the predicate flags, use scan results as scatter indices - **Radix Sort**: each pass of radix sort uses scan to compute output positions — scan of per-digit histograms determines where each element should be placed - **Sparse Matrix Operations**: scan converts CSR (Compressed Sparse Row) row pointer arrays to/from per-element row indices — enables efficient parallel SpMV (Sparse Matrix-Vector multiply) - **Memory Allocation**: parallel dynamic memory allocation uses scan to compute per-thread allocation offsets — each thread declares its allocation size, scan produces non-overlapping offsets - **Run-Length Encoding**: scan of segment flags computes output positions for compressed representation — enables parallel compression of repetitive data **Multi-GPU and Distributed Scan:** - **Hierarchical Approach**: each GPU scans its local partition, exchanges partition totals, scans the totals, and adds offsets to local results — two-phase approach with one inter-GPU communication step - **Communication Cost**: only P values (one per GPU) are exchanged — for thousands of GPUs scanning billions of elements, communication overhead is negligible - **MPI_Scan/MPI_Exscan**: MPI provides built-in prefix scan operations — each process receives the scan of all preceding processes' contributions **Parallel prefix sum demonstrates a profound principle in parallel algorithm design — transforming sequential dependencies into tree-structured computations that expose logarithmic parallelism, enabling what appears to be an inherently sequential operation to execute with near-linear speedup across thousands of processors.**

Go deeper with CFSGPT

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

Create Free Account