flashinfer.top_k_varlen¶
- flashinfer.top_k_varlen(logits: Tensor, seq_lens: Tensor, top_k: int, pre_idx: Tensor | None = None, compress_ratio: int = 1, next_n: int = 1, return_values: bool = False, out_indices: Tensor | None = None, out_values: Tensor | None = None, backend: Literal['radix', 'gvr', 'gvr_2', 'radix_cutlass', 'radix_filter', 'auto'] = 'auto', load_balance: bool = True, workspace: dict | None = None) Tuple[Tensor, Tensor | None]¶
Top-K selection over batched decode-step logits.
Selects the top-
top_kelements from each row oflogits, respecting per-request KV-cache lengths given byseq_lens.Backend selection¶
backend="auto"(default) ranks the backends that can run the call by shape and dtype (see_top_k_varlen_heuristic):gvr_2for hinted fp32 on datacentre Blackwell-class GPUs,radix_filterin the measured large-N regions,gvrfor large hinted half-precision batches of mid-length rows, otherwise the CuTe DSLradixbackend on Blackwell, with theradix_cutlassmasked fallback in its fp32 big corner and on every other GPU. Force a specific backend withbackend="radix","gvr","gvr_2","radix_filter"or"radix_cutlass".- param logits:
2-D float tensor of shape
(num_rows, max_seq_len). Supported dtypes:float32,bfloat16,float16. For the"gvr"backend the row widthmax_seq_lenmust be a multiple of16 // itemsize(8 for fp16/bf16, 4 for fp32) so each row is 16-byte aligned for GVR’s 128-bit vectorized loads; aValueErroris raised otherwise. The"radix_cutlass"backend has no such constraint.- type logits:
torch.Tensor
- param seq_lens:
1-D
int32tensor of shape(num_rows // next_n,)with the effective KV-cache length per request. Logits at or beyondseq_lens[i]are excluded from the search. A row whose length exceeds the logits width (the dynamic length has outgrown the static buffer, e.g. under CUDA-graph replay) is clamped to the width by every backend: only the scores present in the buffer are ranked.- type seq_lens:
torch.Tensor
- param top_k:
Number of top elements per row. GVR backend supports
{512, 1024, 2048}; radix backend has no restriction.- type top_k:
int
- param pre_idx:
int32[num_rows // next_n, top_k]— top-K KV-cache indices selected by this same layer at the previous token’s decode step. GVR exploits the strong correlation between a layer’s attention pattern at steptand stept+1; the kernel internally applies a+1offset (DSv3.2) so the previous step’s indices land correctly in the current step’s grown KV-cache space.pre_idx[:, 0]must be the argmax index. Required by the"gvr"and"gvr_2"backends; ignored by the radix backends. Must be a contiguous, 16-byte-aligned int32 CUDA tensor onlogits.deviceof shape[seq_lens.shape[0], top_k]: a hint that violates this is discarded with a RuntimeWarning and the call runs hint-free (autopicks a hint-free backend; an explicit"gvr"/"gvr_2"request is refused).- type pre_idx:
torch.Tensor, optional
- param compress_ratio:
KV-index compression factor (
1for DSv3.2,4for DSv4). Default1.- type compress_ratio:
int, optional
- param next_n:
Speculative-decode temporal stride. Default
1.- type next_n:
int, optional
- param return_values:
When
Truealso return the selected logit values. DefaultFalse.- type return_values:
bool, optional
- param out_indices:
Pre-allocated
int32[num_rows, top_k]output buffer: contiguous, 16-byte aligned, onlogits.device, of that shape or a 1-D buffer of exactlynum_rows * top_kelements (viewed in place and returned as its[num_rows, top_k]view over the same storage, not as the caller’s object); a wider, taller or otherwise shaped buffer raisesValueError.- type out_indices:
torch.Tensor, optional
- param out_values:
Pre-allocated values buffer (same dtype as
logits, same layout rules asout_indices). Only used whenreturn_values=True.- type out_values:
torch.Tensor, optional
- param backend:
Backend to use. Default
"auto"."radix"— CuTe DSL single-pass multi-CTA radix top-K(Blackwell sm_100+ incl. Rubin sm_107; native varlen, no
pre_idx, no logit masking)."gvr"— GVR kernel (Blackwell sm_100+ only; requirespre_idx).load_balanceselects the LB vs single-CTA path."gvr_2"— self-sampling GVR V2 (TRT-LLM PR #17821 port):sample-calibrated threshold ladders, exact tie-interchangeable top-K, one launch per batch. Datacentre Blackwell-class only (sm_100/103, or Rubin sm_107); requires
pre_idx(hints steer sampling, never exactness) and fp32 logits;top_kin {512, 1024, 2048}.load_balanceis ignored (the kernel families load-balance internally). CUDA graphs: warm up each (num_rows, N, top_k, next_n, compress_ratio) geometry with one eager call before capture (an uncompiled launcher raises loudly under capture); replays may changeseq_lensCONTENTS freely in either direction. All finite values,+infand-infare tie-aware exact (TRT-LLM #18501/#18625 ported); NaN ordering is implementation-specific."radix_cutlass"— Masked CUTLASS radix top-K (all GPUs, nopre_idxneeded)."radix_filter"— DKG filtered-radix top-K (coarse histogram →filter → on-chip refine): hint-free like
"radix", fp32/fp16/bf16,top_kin [1, 16384],compress_ratio == 1only, row-relative indices only (no fused page-table transform, nondeterministic ties). Datacentre Blackwell-class (sm_100/103/107); requires nvidia-cutlass-dsl >= 4.8.pre_idxis accepted and ignored (the kernel takes no hint), as for"radix"and"radix_cutlass"."auto"— shape/dtype-aware selection tracking themeasured per-config winner: gvr_2 for hinted fp32; radix_filter for hint-free fp32 from 32K columns up (all N once
batch >= 256) and for the bf16/fp16 mid/large regions; gvr for fp32 whenbatch * max_seq_len >= 2^22and for half precision only whenbatch >= 256with 32K-512K columns; radix otherwise, with radix_cutlass preferred in its fp32 big-batch/long-row corner. Batches whose rows are mostly far shorter thanmax_seq_lenare a known blind spot (auto cannot readseq_lenswithout a sync); preferbackend="radix"there.
- type backend:
{“radix”, “gvr”, “gvr_2”, “radix_cutlass”, “radix_filter”, “auto”}, optional
- param load_balance:
Selects the GVR kernel path (ignored by the radix backend). Default
True.True(default) — two-kernel LB path (GvrTopKLBPrepareKernel+GvrTopKLBKernel): a prepare kernel classifies requests into long/short buckets, then the main kernel splits each long row across a CTA cluster and packs short rows. Best for the ragged decode batches GVR targets.False— single-kernel path (GvrTopKKernel): one CTA per row,no prepare step. Faster when the batch has no length variance (all rows short, or all long).
Both settings are CUDA-graph safe (no host branch on device data).
- type load_balance:
bool, optional
- param workspace:
Reusable workspace buffers for the GVR
load_balance=Truepath. When provided, the LB prepare and decode kernels read/write these tensors instead of allocating fresh ones per call — useful in decode loops where the same batch size is reused at every step.Required keys (both
int32on the same device aslogits):"gvr_order_row": shape(M,)whereMis the smallest power of 2 in[64, 1024]that is>= seq_lens.shape[0]."gvr_counters": shape(2,).
For the
"gvr_2"backend the optional key"gvr2_workspace"(CUDA tensor of at leastflashinfer.topk_varlen.kernels.gvr2_topk_host.workspace_bytes()= 20,973,568 bytes, zero-initialized before first use, 16-byte aligned) overrides the per-device cached slab.Warning
Do not share the same workspace dict across concurrent CUDA streams — each stream must have its own workspace to avoid races on the device tensors. For the
"gvr"backend,workspace=None(default) allocates per call and is safe for any concurrency. For"gvr_2",workspace=Noneresolves to one slab per device, shared by every launch on that device: it holds the cross-CTA counters, offsets and candidate buffer of the multi-CTA streaming path (selected by the kernel’sroute()from row count, envelope andtop_k; small batches with long rows), so two such launches in flight at once — two eager streams, or two CUDA graphs replayed concurrently — race on it. Every concurrently active stream, and every CUDA graph that may replay concurrently with another launch, must pass its own"gvr2_workspace"; stream-ordered use needs nothing.- type workspace:
dict, optional
- returns:
(indices, values) – Always a 2-tuple.
indicesisint32[num_rows, top_k].valuesholds the selected logits (same dtype aslogits) whenreturn_values=True, otherwiseNone.- rtype:
Tuple[torch.Tensor, Optional[torch.Tensor]]
- raises BackendSupportedError:
If the requested backend is not supported on the current device, or an explicit
"gvr"/"gvr_2"request has no usablepre_idx.- raises ValueError:
If
logits/seq_lens/next_nviolate the shape, dtype or grouping contract, anout_indices/out_valuesbuffer is outside the contract above, or an explicit backend’s checker rejects the problem (reported as “Problem size is not supported”).- Warns:
RuntimeWarning –
pre_idxwas malformed and has been discarded; the call ran hint-free.
Examples
>>> import torch, flashinfer >>> torch.manual_seed(42) >>> B, N_max, top_k = 32, 8192, 1024 >>> >>> # Step t: no prior indices; use radix to get the first top-K. >>> # Each request has a different KV-cache length in [top_k+1, N_max-1]. >>> logits = torch.randn(B, N_max, dtype=torch.bfloat16, device="cuda") >>> seq_lens_t = torch.randint(top_k + 1, N_max, (B,), dtype=torch.int32, device="cuda") >>> indices_t, _ = flashinfer.top_k_varlen(logits, seq_lens_t, top_k, backend="radix_cutlass") >>> # Reference check: every selected value must be >= the K-th largest. >>> for i in range(B): ... s = seq_lens_t[i].item() ... kth = torch.topk(logits[i, :s].float(), top_k).values[-1] ... assert (logits[i, :s].float()[indices_t[i].long()] < kth - 1e-5).sum() == 0 >>> >>> # Step t+1: one new token appended per request; seq_lens grows by 1. >>> logits_t1 = torch.randn(B, N_max, dtype=torch.bfloat16, device="cuda") >>> seq_lens_t1 = seq_lens_t + 1 >>> # Pass indices_t as pre_idx; GVR uses it to warm-start the threshold search. >>> indices_t1, _ = flashinfer.top_k_varlen(logits_t1, seq_lens_t1, top_k, pre_idx=indices_t) >>> for i in range(B): ... s = seq_lens_t1[i].item() ... kth = torch.topk(logits_t1[i, :s].float(), top_k).values[-1] ... assert (logits_t1[i, :s].float()[indices_t1[i].long()] < kth - 1e-5).sum() == 0
See also
flashinfer.top_kGeneral-purpose radix/clusters top-K (uniform lengths).