gpu scan prefix sum

**GPU Scan (Prefix Sum)** is **the parallel algorithm that computes cumulative sums or other associative operations across array elements** — where inclusive scan produces [a0, a0+a1, a0+a1+a2, ...] and exclusive scan produces [0, a0, a0+a1, ...], achieving 400-800 GB/s throughput (50-70% of peak bandwidth) through hierarchical implementation using warp primitives (__shfl_up_sync) for intra-warp (500-1000 GB/s), shared memory for inter-warp (300-600 GB/s), and multi-pass algorithms for large arrays, making scan essential for algorithms like stream compaction (removing elements), radix sort (computing output positions), and sparse matrix operations where scan appears in 30-60% of advanced GPU algorithms and proper implementation using warp-level primitives and minimizing global memory accesses determines whether applications achieve 100 GB/s or 800 GB/s throughput. **Scan Fundamentals:** - **Inclusive Scan**: output[i] = input[0] + input[1] + ... + input[i]; includes current element; natural for cumulative sums - **Exclusive Scan**: output[i] = input[0] + input[1] + ... + input[i-1]; excludes current element; useful for computing positions - **Associative Operations**: sum, max, min, product, AND, OR, XOR; order matters for scan; enables parallelization - **Applications**: stream compaction, radix sort, sparse matrix, work distribution; fundamental building block **Warp-Level Scan:** - **Shuffle Up**: use __shfl_up_sync() in loop; 5 iterations for 32 threads; no shared memory; 2-5× faster than shared memory - **Code Pattern**: for (int offset = 1; offset < 32; offset *= 2) { int temp = __shfl_up_sync(0xffffffff, val, offset); if (lane >= offset) val += temp; } - **Performance**: 500-1000 GB/s; 60-80% of peak bandwidth; 2-5× faster than shared memory; no synchronization overhead - **Use Cases**: scan within warp; building block for block and grid scans; critical optimization **Block-Level Scan:** - **Two-Stage**: warp scan → inter-warp scan → add offsets; optimal at each level; 300-600 GB/s - **Pattern**: each warp scans independently; scan warp sums; add warp offsets to elements; requires two syncs - **Shared Memory**: store warp sums (32-64 elements); minimal usage; enables high occupancy - **Performance**: 300-600 GB/s; 40-60% of peak bandwidth; 2-5× faster than pure shared memory **Large Array Scan:** - **Multi-Pass**: first pass scans blocks independently; second pass scans block sums; third pass adds offsets; 400-800 GB/s - **Three-Kernel**: kernel 1 scans blocks; kernel 2 scans block sums; kernel 3 adds offsets; no global sync needed - **Single-Kernel**: use cooperative groups grid.sync(); simpler but requires all blocks fit on GPU; 400-800 GB/s - **Performance**: 400-800 GB/s for large arrays (>1M elements); 50-70% of peak bandwidth; memory-bound **Optimization Techniques:** - **Warp Primitives**: always use __shfl_up for intra-warp; 2-5× faster than shared memory; 500-1000 GB/s - **Bank Conflict Avoidance**: pad shared memory arrays; prevents bank conflicts; 10-30% improvement - **Coalesced Access**: ensure coalesced memory reads/writes; 128-byte aligned; achieves 100% bandwidth - **Multiple Elements Per Thread**: each thread processes multiple elements; reduces overhead; 20-50% improvement **Inclusive vs Exclusive:** - **Inclusive**: simpler implementation; natural for cumulative sums; output[i] includes input[i] - **Exclusive**: useful for positions; output[i] = sum of elements before i; radix sort, compaction - **Conversion**: exclusive = shift(inclusive, 1) with 0 at start; inclusive = exclusive + input; trivial conversion - **Performance**: same performance; choice based on application needs; exclusive more common in algorithms **Segmented Scan:** - **Concept**: scan multiple independent segments; each segment scanned separately; useful for batched operations - **Implementation**: CUB DeviceSegmentedScan; segment flags or offsets specify boundaries; 300-600 GB/s - **Use Cases**: per-row scan in matrix, per-group aggregation; graph algorithms; sparse matrix operations - **Performance**: 300-600 GB/s; 40-60% of peak; depends on segment sizes; small segments have overhead **Thrust Scan:** - **API**: thrust::inclusive_scan(d_in.begin(), d_in.end(), d_out.begin()); or thrust::exclusive_scan() - **Performance**: 400-800 GB/s; 60-80% of hand-tuned; 1 line vs 100-200 for custom implementation - **Customization**: custom operators supported; thrust::plus(), thrust::maximum(), custom functors - **Use Cases**: rapid development, general-purpose scan; acceptable 20-40% performance gap **CUB Scan:** - **API**: cub::DeviceScan::InclusiveSum(d_temp_storage, temp_storage_bytes, d_in, d_out, N); - **Performance**: 400-800 GB/s; 70-90% of hand-tuned; 10-30% faster than Thrust; lower-level API - **Features**: inclusive, exclusive, custom operators; segmented scan; flexible - **Use Cases**: performance-critical scans; fine-grained control; production systems **Stream Compaction:** - **Pattern**: scan predicate flags; use scan result as output positions; write elements to compacted array - **Code**: flags = predicate(input); positions = exclusive_scan(flags); if (flags[i]) output[positions[i]] = input[i]; - **Performance**: 300-600 GB/s; 40-60% of peak; scan is bottleneck; 2-3× faster than CPU - **Use Cases**: removing elements, filtering; sparse matrix, graph algorithms; data preprocessing **Radix Sort Integration:** - **Histogram**: count elements per bin; 300-600 GB/s - **Scan**: exclusive scan of histogram; computes output positions; 400-800 GB/s - **Scatter**: write elements to sorted positions; 200-300 GB/s - **Performance**: scan is 20-40% of radix sort time; critical for overall performance **Work Distribution:** - **Pattern**: scan work counts; use scan result to assign work to threads; load balancing - **Code**: work_counts = compute_work(input); positions = exclusive_scan(work_counts); assign work based on positions - **Performance**: 300-600 GB/s for scan; enables balanced work distribution; 20-50% improvement in irregular algorithms - **Use Cases**: irregular parallelism, dynamic work assignment; graph algorithms; sparse operations **Hierarchical Patterns:** - **Three-Level**: warp → block → grid; optimal at each level; 400-800 GB/s - **Warp Level**: __shfl_up_sync(); 500-1000 GB/s; no shared memory; no sync - **Block Level**: shared memory for inter-warp; 300-600 GB/s; minimal shared memory usage - **Grid Level**: multi-pass or cooperative groups; 400-800 GB/s; depends on array size **Performance Profiling:** - **Nsight Compute**: shows memory bandwidth, warp efficiency, occupancy; identifies bottlenecks - **Metrics**: achieved bandwidth / peak bandwidth; target 50-70% for scans; memory-bound - **Bottlenecks**: uncoalesced access, bank conflicts, excessive synchronization; optimize patterns - **Tuning**: adjust block size, elements per thread, padding; profile to find optimal **Common Pitfalls:** - **Shared Memory Only**: not using warp primitives; 2-5× slower; always use __shfl_up for intra-warp - **Bank Conflicts**: unpadded shared memory; 2-10× slowdown; add padding to avoid conflicts - **Uncoalesced Access**: stride access patterns; 10-100× slowdown; ensure coalesced reads/writes - **Too Many Syncs**: excessive __syncthreads(); 10-30% overhead each; minimize synchronization **Best Practices:** - **Warp Primitives**: always use __shfl_up for intra-warp scan; 2-5× faster than shared memory - **Hierarchical**: warp → block → grid; optimal at each level; 400-800 GB/s - **Pad Shared Memory**: avoid bank conflicts; 1-2 elements padding; 10-30% improvement - **Coalesced Access**: ensure coalesced memory reads/writes; 128-byte aligned; achieves 100% bandwidth - **Profile**: measure actual bandwidth; compare with peak; optimize only if bottleneck **Performance Targets:** - **Warp Scan**: 500-1000 GB/s; 60-80% of peak; 2-5× faster than shared memory - **Block Scan**: 300-600 GB/s; 40-60% of peak; optimal for 256-512 threads - **Grid Scan**: 400-800 GB/s; 50-70% of peak; for large arrays (>1M elements) - **Overall**: 400-800 GB/s for large arrays; 50-70% of peak bandwidth; memory-bound **Real-World Applications:** - **Stream Compaction**: removing invalid elements; 300-600 GB/s; 40-60% of peak; used in rendering, physics - **Radix Sort**: computing output positions; 400-800 GB/s; 20-40% of sort time; critical for performance - **Sparse Matrix**: CSR format construction; 300-600 GB/s; 30-50% of construction time - **Work Distribution**: load balancing irregular work; 300-600 GB/s; 20-50% improvement in irregular algorithms GPU Scan (Prefix Sum) represents **the essential parallel primitive for position computation** — by using hierarchical implementation with warp primitives for intra-warp (500-1000 GB/s), shared memory for inter-warp (300-600 GB/s), and multi-pass algorithms for large arrays, developers achieve 400-800 GB/s throughput (50-70% of peak bandwidth) and enable algorithms like stream compaction, radix sort, and sparse matrix operations where scan is fundamental building block and proper implementation using warp-level primitives determines whether applications achieve 100 GB/s or 800 GB/s throughput.');

Go deeper with CFSGPT

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

Create Free Account