vllm.models.deepseek_v41.nvidia.specialized_decode.sampling.sharded_markov
¶
DSpark Markov sampling with the Markov head sharded by vocabulary.
After the DSpark backbone produces the base logits of its N draft
positions, the draft tokens are drawn one position at a time: the bias
markov_head @ markov_embed[previous token] ([V, r] by [r]; 66 MB of
BF16 for DeepSeek-V4.1) is added to the position's logits and the token is
sampled from the result. The speculator's loop runs a replicated bias GEMM and
its sampling kernels per position, so every tensor-parallel rank streams the
whole head N times.
Here one cooperative kernel per rank (sharded_markov_cute.py, CuTe DSL)
runs the whole chain. Rank k of world owns rows
[k V / world, (k + 1) V / world) of the head and keeps them in registers
for the launch, so the head is read once; the ranks agree on each position's
winner by exchanging one 64-bit (score, index) key per rank, request row
and position through a mailbox in symmetric memory. A call samples up to 8
request rows (4 with 8 ranks), the columns of the tensor-core MMA. Padding rows
(negative request-state index) are inert, as in the speculator's loop.
Per call::
Triton noise kernel gumbel[i, v] of this rank's vocabulary shard
| (``gumbel_sample``'s hash), drawn on a side
v stream while the draft LM head runs
chain kernel, step i logit = cache_round(base + bf16(head . embed[p]))
local cache and every peer's staging <- logit
key = max over the shard of (logit / T + gumbel, index)
mailbox exchange -> winner p = draft_tokens[i]
chain kernel, tail cache <- the peers' shards from the local staging
The draws reproduce the speculator's gumbel_sample loop (same noise,
rounding, temperature division and torch.argmax tie-breaking) except for
the bias reduction order before its BF16 rounding, so a bias element can differ
from cuBLAS's in its last bit.
With decode_backend=latency_specialized, the DSpark draft model's
sample_sequential (the hook DSparkSpeculator._sample_sequential asks
first) is a ShardedMarkovSampling: batches of up to max_rows request
rows take this chain, larger ones the fused loop of ops/fused_markov.py.
The exchange is a cross-rank spin wait inside the draft step (and its FULL CUDA graph): every rank must launch the kernel the same number of times. Installation depends on configuration only and is agreed across the group, and the per-call choice depends only on the padded batch shape, which tensor parallelism keeps identical across ranks; a rank that diverges hangs.
Classes:
-
DSparkShardedMarkovSampler–Persistent buffers, peer mappings and launchers of the sharded chain.
-
ShardedMarkovSampling–The DSpark draft model's
sample_sequentialhook: the sharded chain
Functions:
-
build_sharded_markov_sampling–Wrap
fusedwith the sharded chain where supported, agreed by all ranks. -
make_sharded_sampler–The sampler on every rank of
group, or None on every rank (logged). -
unsupported_reason–Why the sharded sampler cannot serve this configuration, or None. It
DSparkShardedMarkovSampler
¶
Persistent buffers, peer mappings and launchers of the sharded chain.
embed_weight [V, 256] and the replicated head_weight
[V, 256] are BF16; this rank keeps a view of its head rows. group
is the CPU group of the tensor-parallel ranks (None for one rank).
timeout_ms bounds every cross-rank wait with a trap (0: no bound, a
debugging aid). Batches of up to max_rows request rows, CUDA-graph
padding included, take the sharded chain.
Methods:
-
accepts_shard–Whether, on every rank,
shard(the first column and width of -
fork_noise–Draw this call's noise on a side stream after the current stream's
-
sample–Draw every request row's draft tokens into
draft_tokens[row]and -
supports–Whether a call with these
[num_reqs, num_steps, V]base logits, -
supports_batch–Whether a batch of
num_reqsrequest rows (padding included) can
Source code in vllm/models/deepseek_v41/nvidia/specialized_decode/sampling/sharded_markov.py
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 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 | |
_allocate_peer_buffer(size)
¶
The zeroed mailbox and staging buffer and every rank's mapping of it (symmetric memory for more than one rank).
Source code in vllm/models/deepseek_v41/nvidia/specialized_decode/sampling/sharded_markov.py
accepts_shard(shard)
¶
Whether, on every rank, shard (the first column and width of
the draft LM head's local logits) is this rank's vocabulary shard. A
CPU collective: a rank that skipped the LM head's all-gather would
leave its peers waiting in it.
Source code in vllm/models/deepseek_v41/nvidia/specialized_decode/sampling/sharded_markov.py
fork_noise(idx_mapping, sample_pos, seeds)
¶
Draw this call's noise on a side stream after the current stream's
work so far; join_noise must follow before sample. The noise
depends on the seeds and positions only, not on the chain.
Source code in vllm/models/deepseek_v41/nvidia/specialized_decode/sampling/sharded_markov.py
sample(base_logits, input_ids, query_per_row, idx_mapping, temperature, logits_cache, draft_tokens)
¶
Draw every request row's draft tokens into draft_tokens[row] and
the full-vocabulary logits of rows with a request state into
logits_cache[idx_mapping], with the noise of fork_noise.
base_logits is [rows, num_steps, V] or this rank's
[rows, num_steps, V / world] shard; row r's anchor token is
input_ids[r * query_per_row]; idx_mapping is the
[rows * num_steps] request-state row (negative for padding).
Source code in vllm/models/deepseek_v41/nvidia/specialized_decode/sampling/sharded_markov.py
supports(num_reqs, base_logits)
¶
Whether a call with these [num_reqs, num_steps, V] base logits,
or this rank's [num_reqs, num_steps, V / world] shard of them,
takes the sharded chain. Depends on shapes and dtypes only.
Source code in vllm/models/deepseek_v41/nvidia/specialized_decode/sampling/sharded_markov.py
supports_batch(num_reqs)
¶
Whether a batch of num_reqs request rows (padding included) can
take the sharded chain; the same on every rank.
Source code in vllm/models/deepseek_v41/nvidia/specialized_decode/sampling/sharded_markov.py
ShardedMarkovSampling
¶
The DSpark draft model's sample_sequential hook: the sharded chain
for the batches it takes, fallback (the fused loop) for the others.
local_logits (agreed by every rank) has the chain read this rank's
vocabulary shard of the draft logits, skipping their all-gather.
Methods:
-
__call__–Draw the draft tokens of
num_reqsrequest rows (the padded
Source code in vllm/models/deepseek_v41/nvidia/specialized_decode/sampling/sharded_markov.py
__call__(spec, num_reqs, head_hidden)
¶
Draw the draft tokens of num_reqs request rows (the padded
batch, the same on every rank) into spec.draft_tokens and cache
their logits; returns True, as the fused loop does.
Source code in vllm/models/deepseek_v41/nvidia/specialized_decode/sampling/sharded_markov.py
_all_ranks_true(group, value)
¶
Whether value holds on every rank of group (CPU collective).
Source code in vllm/models/deepseek_v41/nvidia/specialized_decode/sampling/sharded_markov.py
_kernel(device_index, steps, base_dtype, cache_dtype)
cached
¶
The CuTe DSL chain kernel compiled for a device, steps draft
positions and the base-logits and cache dtypes. Its 512-thread CTA fits one
per SM, and a call never launches more CTAs than the device has SMs, so the
cooperative grid is always co-resident.
Source code in vllm/models/deepseek_v41/nvidia/specialized_decode/sampling/sharded_markov.py
_shard_noise_kernel(noise_ptr, idx_mapping_ptr, sample_pos_ptr, seeds_ptr, vocab_offset, vocab_local, num_steps, BLOCK)
¶
Draft Gumbel noise of this rank's vocabulary shard for one (request row,
position), as gumbel_noised_argmax draws it (fp32, drafting salt) with
the draft step mixed into the seed. Samples are ordered (row, step).
Source code in vllm/models/deepseek_v41/nvidia/specialized_decode/sampling/sharded_markov.py
build_sharded_markov_sampling(model, fused)
¶
Wrap fused with the sharded chain where supported, agreed by all ranks.
Source code in vllm/models/deepseek_v41/nvidia/specialized_decode/sampling/sharded_markov.py
make_sharded_sampler(embed_weight, head_weight, vocab_size, num_steps, cache_dtype, group, max_num_reqs)
¶
The sampler on every rank of group, or None on every rank (logged).
Every rank must call this: the decision and the set-up are agreed with CPU
collectives. head_weight None means this rank cannot install it.
Source code in vllm/models/deepseek_v41/nvidia/specialized_decode/sampling/sharded_markov.py
unsupported_reason(world, vocab_size, num_steps, embed_weight, head_weight, cache_dtype)
¶
Why the sharded sampler cannot serve this configuration, or None. It depends on configuration only, so every rank reaches the same answer.