Skip to main content

Module kernels

Module kernels 

Source
Expand description

Parallel sparse × dense kernels.

§Why there are two kernels

A compressed matrix can only be walked along its outer dimension. For a CSR matrix that is rows, so:

  • A · D writes output row i from sparse row i. Threads own disjoint output rows, so this needs no scratch and no reductiongather_mul.
  • Aᵀ · D reads sparse row i and scatters into output rows j for every column j present in that row. Threads collide, so accumulation is needed — scatter_mul.

transpose_view() does not escape this: it relabels a CSR matrix as a CSC view of the transpose, but the traversable dimension is unchanged. What it does buy is that a CSC-stored matrix gets the disjoint kernel for Aᵀ · D for free, so callers holding CSC pay nothing for the transposed direction.

§Scratch budgeting

The 1.x code allocated one full n × k buffer per chunk, with chunk count driven by matrix size — 64 chunks on a 200k-row matrix, so ~922 MiB of scratch for a single 30000 × 60 product. Here the accumulator count is the thread count, and if threads × n × k still exceeds DEFAULT_SCRATCH_BUDGET the dense columns are processed in blocks so the bound always holds.

Constants§

DEFAULT_SCRATCH_BUDGET
Upper bound on transient scratch for scatter-direction products, in bytes.

Functions§

gather_mul
out = lhs · rhs where lhs is CSR. Write-disjoint: no scratch, no reduction.
gather_mul_vec
y = lhs · x where lhs is CSR. Write-disjoint.
scatter_mul
out = lhsᵀ · rhs where lhs is CSR. Scatter direction: uses one accumulator per thread, blocking over the columns of rhs to keep scratch under budget.
scatter_mul_vec
y = lhsᵀ · x where lhs is CSR. Scatter direction, one accumulator per thread.