vllm.v1.worker.gpu.spec_decode.xpress.kernels
¶
Triton kernels for one XPress Jacobi pass.
A pass over a batch of N blocks (B slots each, slot 0 = the verified anchor) is:
latent u[n, b, :] = causal_mix(hcache[n, b] + embed(prev[n, b]) @ W_lat)
x[n, b, :] = u[n, b, :] + SwiGLU_MLP(u[n, b, :])
readout logits[n, b, :] = base[n, b, :] + x[n, b, :] @ W2 (a matmul)
argmax blk[n, b] = argmax_v logits[n, b, v]
Only the latent and argmax stages are custom. The latent stage is a dozen tiny ops per block that torch launches separately; fusing them removes the launch floor, which is what bounds a small head. The argmax stage would otherwise materialize [N * (B - 1), V] bf16 logits per pass (~146 MB at N = 32, V = 152k) only to reduce them; fusing the add into the reduction never writes them.
Functions:
-
fused_add_argmax_to_blk–blk[n, 1 + b] = argmax_v(base[r, v] + bias[r, v])for row r = n * (B-1) + b. -
fused_topc_argmax_to_blk–Run
_xpress_topc_argmax_to_blk_kernel; see it for shapes. -
xpress_latent_pass–Run
_xpress_latent_kernelover N blocks; see its docstring for shapes.
_xpress_add_argmax_partial_kernel(base_ptr, bias_ptr, out_val_ptr, out_idx_ptr, V, stride_base_r, stride_bias_r, stride_ov_r, stride_oi_r, BLOCK_V)
¶
Stage 1 of the fused argmax: per (row, vocab chunk) max and its index.
Grid: (ceil(V / BLOCK_V), rows). Each program sums one BLOCK_V-wide chunk of
base[row] + bias[row] in registers and reduces it, so the full [rows, V]
sum is never stored.
Parameters:
-
(base_ptr¶tensor) –[rows, V] base logits (bf16), row stride
stride_base_r. -
(bias_ptr¶tensor) –[rows, V] refiner bias, same layout.
-
(out_val_ptr¶tensor) –[rows, num_chunks] fp32 chunk maxima (written).
-
(out_idx_ptr¶tensor) –[rows, num_chunks] int64 chunk argmax, in vocab ids (written).
-
(V¶int) –vocabulary size; the last chunk is masked to it.
-
(stride_base_r¶int) –row stride of
base_ptr. -
(stride_bias_r¶int) –row stride of
bias_ptr. -
(stride_ov_r¶int) –row stride of
out_val_ptr. -
(stride_oi_r¶int) –row stride of
out_idx_ptr. -
(BLOCK_V¶constexpr) –vocab chunk width per program.
Source code in vllm/v1/worker/gpu/spec_decode/xpress/kernels.py
_xpress_add_argmax_reduce_to_blk_kernel(out_val_ptr, out_idx_ptr, blk_ptr, N, Bm1, stride_ov_r, stride_oi_r, BLOCK_N)
¶
Stage 2 of the fused argmax: reduce one row's chunk maxima into blk.
Grid: (rows,). Row r is slot 1 + r % (B - 1) of block r // (B - 1);
the winner is written to blk[n, slot] so the next pass reads it in place.
Source code in vllm/v1/worker/gpu/spec_decode/xpress/kernels.py
_xpress_latent_kernel(blk_ptr, am1_ptr, xh_ptr, lat_out_ptr, w1_ptr, wlat_ptr, mixl_ptr, wg_ptr, wu_ptr, wd_ptr, B, R, H, BP, HT, DO_MLP)
¶
The latent stage of one Jacobi pass for one block, fused end to end.
Grid: (N,), one program per block. For every slot b it gathers the previous
slot's token embedding (slot 0 reads the anchor's predecessor am1),
adds the pass-invariant hidden cache, applies the folded causal mixer
u[b] = sum_{j <= b} L[b, j, :] * x[j], then a SwiGLU MLP with a
residual, and writes the latent for slots 1..B-1 (slot 0 is the anchor and
is never read out).
Parameters:
-
(blk_ptr¶tensor) –[N, B] int64 current block tokens; slot b reads
blk[b - 1]. -
(am1_ptr¶tensor) –[N] int64 token preceding each block's anchor.
-
(xh_ptr¶tensor) –[N, B, R] hidden cache,
down_h(h) ++ down_g(mean h)projected to R, constant across passes. -
(lat_out_ptr¶tensor) –[N, B - 1, R] latent output (written).
-
(w1_ptr¶tensor) –[V, R] token embedding.
-
(wlat_ptr¶tensor) –[R, R] embedding-to-latent projection (transposed).
-
(mixl_ptr¶tensor) –[B, B, R] folded mixer
L * tril + I, per channel. -
(wg_ptr¶tensor) –[R, H] SwiGLU gate (transposed).
-
(wu_ptr¶tensor) –[R, H] SwiGLU up (transposed).
-
(wd_ptr¶tensor) –[H, R] SwiGLU down (transposed).
-
(B¶constexpr) –block size.
-
(R¶constexpr) –latent rank.
-
(H¶constexpr) –MLP hidden size.
-
(BP¶constexpr) –B rounded up to a power of two (tile size).
-
(HT¶constexpr) –MLP hidden tile size.
-
(DO_MLP¶constexpr) –whether to run the SwiGLU MLP here. False stops after the mixer and hands its output back, so the caller can run the SwiGLU as cuBLAS GEMMs instead -- see the comment at the MLP loop for why that is faster.
Source code in vllm/v1/worker/gpu/spec_decode/xpress/kernels.py
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | |
_xpress_topc_argmax_to_blk_kernel(base_ptr, bias_ptr, cand_ptr, blk_ptr, C, B, BLOCK_C)
¶
Argmax over a slot's C candidates, written straight back as a token id.
Grid: (N * (B - 1),), one program per draft slot. The candidate axis fits in one block at the C values this path uses, so unlike the full-vocab epilogue there is no partial/reduce split; the gather from candidate index to vocab id happens in the same program, which removes a second kernel and its round trip.
Parameters:
-
(base_ptr¶tensor) –[rows, C] base logits gathered at the candidates (bf16).
-
(bias_ptr¶tensor) –[rows, C] refiner bias on the same candidates.
-
(cand_ptr¶tensor) –[rows, C] int64 vocab ids of the candidates.
-
(blk_ptr¶tensor) –[N, B] int64 block tokens; slot j of row n is written at j + 1.
-
(C¶int) –candidates per slot.
-
(B¶constexpr) –block size, to map a row back to its (block, slot).
-
(BLOCK_C¶constexpr) –C rounded up to a power of two.
Source code in vllm/v1/worker/gpu/spec_decode/xpress/kernels.py
fused_add_argmax_to_blk(base, bias, out_val, out_idx, blk, block_v=4096)
¶
blk[n, 1 + b] = argmax_v(base[r, v] + bias[r, v]) for row r = n * (B-1) + b.
The [rows, V] sum is never materialized: stage 1 reduces it chunk-wise in registers, stage 2 reduces the chunk maxima and scatters the winner into the block buffer, so one pass stays at three launches inside the captured graph.
Parameters:
-
(base¶Tensor) –[N * (B - 1), V] base logits for the draft slots.
-
(bias¶Tensor) –[N * (B - 1), V] refiner bias for the same rows.
-
(out_val¶Tensor) –[rows, ceil(V / block_v)] fp32 scratch for the chunk maxima.
-
(out_idx¶Tensor) –[rows, ceil(V / block_v)] int64 scratch for the chunk argmax.
-
(blk¶Tensor) –[N, B] int64 block buffer; slots 1..B-1 are written.
-
(block_v¶int, default:4096) –vocab chunk width for stage 1; sets the scratch width.
Source code in vllm/v1/worker/gpu/spec_decode/xpress/kernels.py
fused_topc_argmax_to_blk(base_c, bias_c, cand, blk)
¶
Run _xpress_topc_argmax_to_blk_kernel; see it for shapes.
Source code in vllm/v1/worker/gpu/spec_decode/xpress/kernels.py
xpress_latent_pass(blk, tok_am1, xh, lat_out, w1_weight, wlat_t, mix_kjc, wg_t, wu_t, wd_t, do_mlp=True)
¶
Run _xpress_latent_kernel over N blocks; see its docstring for shapes.
The caller follows this with the readout matmul lat_out @ W2 and one of
the fused argmax entry points below.