Skip to main content

GPUSegmentedScan

Overview

GPUSegmentedScan computes independent prefix sums over variable-length contiguous ranges described by offset-delimited segments.

At a glance

QuestionAnswer
ProblemCompute independent prefix sums over offset-delimited packed segments.
Reads / writesReads packed uint32 values and segment offsets; writes source-aligned prefixes.
OwnershipPublic inputs and outputs are caller-owned; scratch storage is graph-owned transient memory.
Output contractOne exclusive or inclusive prefix per input row, reset at each segment boundary.
Expected workOne workgroup per segment in the baseline implementation.
ChunksConsumes one packed value domain with explicit CSR-style offsets.
Conditions / budgetsMay be conditioned with its dependent branch; encoding, submission, and publication remain application-owned.
Neighborhoodsegment offsets + values → GPUSegmentedScan → local ranks or offsets.

Prefix scans and segmented scans

A prefix scan turns values into running totals. For example, an exclusive scan of:

input = [2, 3, 4, 5]
output = [0, 2, 5, 9]

while the inclusive form is:

output = [2, 5, 9, 14]

A segmented scan packs several independent sequences into one buffer and resets the running total at each boundary:

values = [2, 3 | 4, 5, 6 | 7]
offsets = [0, 2, 5, 6]

exclusive = [0, 2 | 0, 4, 9 | 0]
inclusive = [2, 5 | 4, 9,15 | 7]

Segment s is [offsets[s], offsets[s + 1]). N segments require N+1 offsets; repeated offsets describe empty segments. This general representation also appears in Arrow lists, graph adjacency and CSR matrices, but the segmented API is not matrix-specific.

Why it matters

Many GPU structures contain thousands of logical lists packed into one allocation. They need local ranks, local allocation positions or prefix weights without launching a separate scan for every list. A canonical segmented scan makes that operation reusable.

Contract

The initial operation consumes packed uint32 values and segmentOffsets. The output has the same length as the input and supports exclusive and inclusive modes.

graph.add(new GPUSegmentedScan({
input: weights,
segmentOffsets,
output: prefixWeights,
mode: 'exclusive'
}));

Empty segments are valid and write no rows.

Composition

sort / RLE / grouping / sparse construction

segmentOffsets

GPUSegmentedScan

local ranks / offsets / positions

Together with GPUSegmentedReduction, this establishes the basic segmented algebra needed by grouped aggregation, graph adjacency processing, sparse structures and columnar list data.

Performance notes

The first implementation establishes the API before optimizing execution: one workgroup is assigned per segment and one lane currently scans that segment serially. This is a correctness baseline and is appropriate only for small segments.

The intended optimized implementation uses parallel workgroup scans for medium segments, subgroup collectives when available, and hierarchical strategies for very large segments. Highly skewed segment distributions require strategy selection to avoid poor GPU utilization. None of those optimizations requires changing the offset-delimited contract.

Limitations

The initial primitive supports uint32 addition only. Input/output aliasing is rejected. Offsets are assumed monotonic and within input bounds; producers establish those GPU-resident invariants without requiring readback.