Low Rank Candidate Head Kernels#
-
class LowRankCandidateHeadRunner#
Fused low-rank candidate head: K0 s = fp16(hidden downProj^T); for passes above 8 rows, or every pass when upProj fits in L2, a pilot bound per row from the maxima of sampled upProj tiles; K1 tensor-core low-rank scores of every vocab row with a per-CTA streaming top-Kc (upProj read once per pass, scores never written); K2 merge of the per-CTA lists, lmHead gather-dot, sort by (exact logit desc, id asc), then log_softmax over the Kc exact logits.
Public Functions
- LowRankCandidateHeadRunner(
- LowRankCandidateHeadShape shape,
- int32_t maxRows,
- cudaDeviceProp const &prop
Picks the per-device configuration (rows per pass, tile, stages, survivor capacity, grid) from prop’s SM version, SM count and shared-memory limit, and sets the kernel attributes on the current device, whose occupancy queries size the grids (prop normally describes the current device). Throws for unsupported shapes or devices (SM < 80).
-
size_t workspaceBytes() const noexcept#
- void run(
- rt::Tensor const &hidden,
- rt::Tensor const &downProj,
- rt::Tensor const &upProj,
- rt::Tensor const &lmHead,
- rt::Tensor &candidateIds,
- rt::Tensor &candidateLogProbs,
- void *workspace,
- cudaStream_t stream
hidden [R, H] fp16 with 0 <= R <= maxRows; downProj [r, H], upProj [V, r], lmHead [V, H] fp16, all 16-byte aligned. Writes candidateIds [R, Kc] int32 and candidateLogProbs [R, Kc] fp32 sorted by (logit desc, id asc). workspace: workspaceBytes() of scratch; no state persists across calls. No allocation and no host sync, so the call can be captured in a CUDA graph.
Public Static Functions
- static size_t workspaceBytes(
- LowRankCandidateHeadShape shape,
- int32_t maxRows,
- cudaDeviceProp const &prop
Same configuration rules (and current-device queries) as the constructor.
- static size_t minimumWorkspaceBytes(
- LowRankCandidateHeadShape shape,
- int32_t maxRows,
- cudaDeviceProp const &prop
The smallest workspace that any configuration withinWorkspace may choose needs on this device; results do not depend on the configuration, only the speed does.
- static LowRankCandidateHeadRunner withinWorkspace(
- LowRankCandidateHeadShape shape,
- int32_t maxRows,
- cudaDeviceProp const &prop,
- size_t workspaceLimit
The device’s preferred runner if its workspace fits
workspaceLimit, else the first of a fixed sequence of smaller configurations (fewer pilot witnesses, no pilot, smaller survivor buffers, fewer CTAs per pass) that fits. Throws when none does, that is below minimumWorkspaceBytes.
Public Static Attributes
-
static constexpr int32_t kMaxRowsPerPass = 64#
Largest pass: workspaceBytes(shape, maxRows) is the same for every maxRows >= kMaxRowsPerPass and never larger below it.
-
struct LowRankCandidateHeadShape#
Dimensions of a low-rank candidate head: hidden [R, hiddenSize], downProj [rank, hiddenSize], upProj [vocabSize, rank], lmHead [vocabSize, hiddenSize]; numCandidates (Kc) candidates per row.
-
struct LowRankCandidateHeadBucket#
Selection-kernel (K1) launch configuration for passes of up to maxRows rows.
Public Members
-
int32_t maxRows = {0}#
Largest pass row count served by this bucket (8, 16, 32 or 64).
-
int32_t capacity = {0}#
Survivor entries per row (CAP).
-
int32_t grid = {0}#
K1 CTAs (P); CTA p scans vocab slab p.
-
int32_t slabRows = {0}#
Vocab rows per slab (a multiple of 16, at most 65536).
-
int32_t listHead = {0}#
Each per-CTA candidate list stores its listHead largest keys first.
-
int32_t pilotTiles = {0}#
Sample tiles whose per-row maxima seed the row thresholds (0: no pilot).
K1 dynamic shared memory.
-
int32_t maxRows = {0}#
-
struct LowRankCandidateHeadConfig#
Per-device configuration, fixed at construction. Results never depend on it.
Public Members
-
int32_t smVersion = {0}#
-
int32_t numSMs = {0}#
-
int32_t rowsPerPass = {0}#
Rp: R > Rp runs in ceil(R / Rp) passes, each re-reading upProj once.
-
int32_t tileRows = {0}#
T: upProj rows per pipeline stage.
-
int32_t stages = {0}#
S: pipeline depth.
-
int32_t projectionSplits = {0}#
K0 k splits (depends on hiddenSize only).
K2 dynamic shared memory.
-
int32_t k2CtasPerWave = {0}#
K2 CTAs that are co-resident on the device.
-
std::array<int32_t, kMaxK2Groups + 1> k2ClustersPerWave = {}#
Co-resident (1, G, 1) K2 clusters for each G (0 where G cannot be placed); used when useCluster is set.
-
bool usePdl = {false}#
K1 and K2 use programmatic dependent launch (SM90+).
-
bool useCluster = {false}#
K2 merges once per row through a (1, G, 1) cluster (SM90+).
-
bool evictFirstA = {false}#
upProj streams with an L2 evict-first policy (upProj does not fit in L2).
-
int32_t numBuckets = {0}#
-
std::array<LowRankCandidateHeadBucket, kMaxBuckets> buckets = {}#
-
int32_t smVersion = {0}#