vllm.models.kimi_k3.nvidia.specialized_decode.cutedsl.mla.query_wide
¶
The MLA query at many local heads (TP1 / DEP: all 96 heads on one GPU), and at TP8 / DCP8 (12 heads) from SPLIT_FROM rows, as three kernels instead of MlaQuery's one:
QueryNorm the q_a RMSNorm -> the q_c rows [B, 1536] (dsa.overlap.QueryNorm, bit-identical to MlaQuery's normalization) Q_B q_c @ Q_B^T -> the BF16 query rows [B, H * 192] (split-K projection: one 128-row weight tile per SM at H = 96, the weight streamed once) MlaAbsorb the W_UK absorption of each head's 128 nope columns, the 64 rope columns and the MLA KV insert -> the query rows [B, H, 576]
MlaQuery gives every (head, Q_B slice) its own CTA of a cluster that stages and normalizes every token row itself: at 96 heads that is 768-1536 CTAs, each re-reading the input rows and running the RMSNorm, several waves of a latency-bound chain (75 us at 5 rows, 306 us at 80 rows on GB300). Split, the Q_B weight (56.6 MB at 96 heads) streams through one GEMM wave and the absorption reads W_UK once per 16 tokens.
Numerics are MlaQuery's: Q_B accumulates in FP32 and rounds to BF16, the absorption takes the BF16 nope rows, accumulates in FP32 (BF16 MMA) and rounds to BF16 before the per-tensor FP8 query scale (fp8_ds_mla: the BF16 query); the KV insert is MlaQuery's own (insert / insert_ds / insert_nvfp4).
Classes:
-
MlaAbsorb–W_UK absorption, rope columns and MLA KV insert from the Q_B rows. One
-
MlaQuant–The query rows from the W_UK bmm's BF16 latent [H, B, 512] (in MlaAbsorb's
Functions:
-
absorb_bmm–Whether
batchrows ofheadslocal heads absorb by the W_UK bmm. -
absorb_splits–CTAs per (part, head) of MlaAbsorb: each takes every splits-th token tile.
-
absorb_tokens–Tokens per MlaAbsorb tile: 16 up to 16 rows, 32 up to 32, else 64; below
-
fi_heads–The FlashInfer sparse MLA query heads of
headslocal heads: 64 < H < 128 -
split_query–Whether the MLA query of
batchrows atheadslocal heads runs split -
wide_query–Whether the MLA query of
headslocal heads runs split at every batch.
MlaAbsorb
¶
Bases: MlaQuery
W_UK absorption, rope columns and MLA KV insert from the Q_B rows. One
128-thread CTA per (128 latent columns, head): 384 CTAs at 96 heads, one wave
at three per SM. It stages its 32 KB W_UK slice once, then walks the batch in
tiles of absorb_tokens tokens (the next tile's rows load while the current
one's output stores); warp w owns latent columns 32w..32w+31 of the part for
every 16-token MMA tile (BF16 MMA, FP32 accumulation, K = 128). The four parts
of a head share its rope columns, every CTA one KV insert per 4H tokens.
One CTA per (part, head, tile) instead ran 1920 CTAs at 320 rows, each a latency-bound chain (W_UK, PDL wait, rows, MMAs, stores): 36 us against 1.5 us of W_UK bytes.
Small head counts (TP8 / DCP8: 12) split each (part, head)'s token tiles over
absorb_splits CTAs (grid z), each staging the W_UK slice.
dcp (with q_heads): each CTA also multicasts the query bytes it stores
(latent columns, rope columns) into head block rank of every rank's q
mailbox, as MlaQuery.publish; QueryWait polls it (no poll here).
Arguments as MlaQuery's with the Q_B rows [B, H * 192] (BF16) in place of the Q_B weight: (packed rows, q_a norm, kv_a norm, Q_B rows, W_UK, MLA cache, slots, 1 / q_scale, k_scale, eps, query rows[, q mailbox, its multicast address, rank], stream).
Methods:
-
publish_words–DCP:
words(the query bytes oftoken's headheadfrom column -
rope–The rope columns of the tile's tokens (8 per 16 B chunk, the PARTS CTAs
-
stage_rows–cp.async the nope columns of tokens tok0 .. tok0 + T into
qn.
Source code in vllm/models/kimi_k3/nvidia/specialized_decode/cutedsl/mla/query_wide.py
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 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 | |
publish_words(args, token, head, col, words)
¶
DCP: words (the query bytes of token's head head from column
col) into head block rank of every rank's q mailbox.
Source code in vllm/models/kimi_k3/nvidia/specialized_decode/cutedsl/mla/query_wide.py
rope(q_rows, output, qsi, tok0, part, head, tid, args=())
¶
The rope columns of the tile's tokens (8 per 16 B chunk, the PARTS CTAs of a head take every PARTS-th chunk): every load issued before the stores.
Source code in vllm/models/kimi_k3/nvidia/specialized_decode/cutedsl/mla/query_wide.py
stage_rows(q_rows, qn, tok0, head, tid)
¶
cp.async the nope columns of tokens tok0 .. tok0 + T into qn.
Source code in vllm/models/kimi_k3/nvidia/specialized_decode/cutedsl/mla/query_wide.py
MlaQuant
¶
Bases: MlaAbsorb
The query rows from the W_UK bmm's BF16 latent [H, B, 512] (in MlaAbsorb's W_UK argument): the per-tensor FP8 query (latent and the Q_B rows' rope columns times 1 / q_scale, as MlaAbsorb), the MLA KV insert and, under DCP, the q mailbox publish. One 128-thread CTA per (head, split): thread i of the CTA converts 16 B chunks i, i + 128, .. of the head's B x 72 chunks (64 latent, 8 rope); CTA (head, split) inserts tokens split * H + head, + H * S, ..
Source code in vllm/models/kimi_k3/nvidia/specialized_decode/cutedsl/mla/query_wide.py
absorb_bmm(heads, batch)
¶
Whether batch rows of heads local heads absorb by the W_UK bmm.
absorb_splits(batch, heads)
¶
CTAs per (part, head) of MlaAbsorb: each takes every splits-th token tile.
Source code in vllm/models/kimi_k3/nvidia/specialized_decode/cutedsl/mla/query_wide.py
absorb_tokens(batch, heads=WIDE_HEADS)
¶
Tokens per MlaAbsorb tile: 16 up to 16 rows, 32 up to 32, else 64; below WIDE_HEADS heads (the tiles then spread over CTAs) at most 32.
Source code in vllm/models/kimi_k3/nvidia/specialized_decode/cutedsl/mla/query_wide.py
fi_heads(heads)
¶
The FlashInfer sparse MLA query heads of heads local heads: 64 < H < 128
zero-padded to 128 (trtllm-gen takes <= 64 or exactly 128 heads; prims_ts
before flashinfer-ai/flashinfer#7984 runs other counts as two M64 tiles that
load every KV row twice: at 96 heads 2.0-2.1x slower from 80 rows, GB300 128K,
101.9 / 149.3 / 244.7 us at 80 / 160 / 320 rows against 50.7 / 72.4 / 112.6
padded). The stock decode pads only on such builds
(FlashInferMLASparseImpl._prims_ts_query_heads); the pad heads are zero, so
both head counts compute the same rows.
Source code in vllm/models/kimi_k3/nvidia/specialized_decode/cutedsl/mla/query_wide.py
split_query(heads, batch, dcp=0)
¶
Whether the MLA query of batch rows at heads local heads runs split
(QueryNorm, the Q_B projection, MlaAbsorb): always from WIDE_HEADS heads, else
from SPLIT_FROM rows (under DCP MlaAbsorb publishes into the q mailbox).
Source code in vllm/models/kimi_k3/nvidia/specialized_decode/cutedsl/mla/query_wide.py
wide_query(heads)
¶
Whether the MLA query of heads local heads runs split at every batch.