You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
DeepSeek-V4-Flash on SM120 (enabled by #43477) crashes with CUDA error: an illegal memory access was encountered on all TP ranks → EngineDeadError, on the first prefill batch containing a request longer than ~2048 tokens (e.g. 16 concurrent structured-output requests with 0.5–8K-token prompts; also a single ~5K-token prompt). Short prompts serve perfectly. We reproduced the crash 9 times across vLLM 0.25.1/0.26.0 and flashinfer 0.6.13/0.6.14/0.6.15.
Under CUDA_LAUNCH_BLOCKING=1, the fault is raised in the Triton kernel _compute_global_topk_indices_and_lens_kernel (vllm/models/deepseek_v4/common/ops/cache_utils.py), reached from DeepseekV4FlashInferSM120Attention._forward_prefill (compress-ratio-4 branch).
Root-cause chain (instrumented at the tensor level)
1. fp8_fp4_mqa_logits produces NaN-dominated logits on SM120.
Auditing the valid [ks, ke) region of the prefill MQA logits per C4A layer on a single 4,972-token prefill: the first C4A layer is 83% NaN (2,560,388 of 3,088,855 entries; the finite remainder looks plausible, range ≈ −2…4), and every subsequent layer is 100% NaN (cascade through the model). This is presumably the SM12x scale-handling issue (cf. the e8m0→fp32 upcast in #41834).
2. top_k_per_row_prefill mishandles NaN input on its histogram path and emits uninitialized shared memory as indices.
Auditing topk_indices_buffer immediately after ops.top_k_per_row_prefill returns: rows whose candidate count rowLen = ke−ks ≤ topk (the short-row path) are clean (-1-padded as documented); rows with rowLen > topk (histogram path) contain garbage starting at exactly the first such row, e.g. rows 2051…4868 of a 4,869-token request at compress ratio 4 (2051/4 ≈ 513 > 512 = index_topk). Garbage row counts differ across TP ranks on identical input (1923/2151/2120/1987) — nondeterministic, consistent with uninitialized dynamic shared memory (smemOutput is never pre-initialized and the final copy loop writes all topK slots).
This reproduces in isolation, without serving (25 lines, below): with clean random logits the kernel is correct on SM120 (0 garbage rows, and tests/kernels/test_top_k_per_row.py passes 12/12 here); with 83%-NaN logits, ~40% of histogram-path rows contain garbage. Two distinct failure signatures:
indices equal to 2143289344 = 0x7FC00000 — a float32 NaN bit pattern reinterpreted as an int32 index;
output slots that keep their pre-launch canary value — i.e. never written at all (in serving these become whatever is in shared memory).
Since the repro is data-driven (NaN input) rather than SM120-specific, the kernel's NaN mishandling likely affects all architectures; SM120 is where NaN logits actually occur in practice.
3. compute_global_topk_indices_and_lens dereferences the garbage.
Its validity mask is only local_idx >= 0, so INT32_MAX-class indices pass and it gathers block_table[req, idx // block_size] far out of bounds → the illegal memory access that kills the engine.
Behavioral confirmation
Needle-in-haystack on the same server: a prompt below the sparse threshold retrieves the needle perfectly ("The secret code word is BLUEBERRY."); the identical needle in a ~4.5K-token prompt yields output completely unrelated to the prompt (the model hallucinates arbitrary code/text — its selected KV set is effectively random). Short prompts mask defect (1) entirely because when rowLen ≤ topk the top-k selects all candidates and scores never matter.
Suggested fixes (layered)
Kernel hardening (csrc/libtorch_stable/sampler.cu): the histogram path should never emit unwritten smem or NaN bit patterns as indices — pad under-filled output with -1 like the short-row path, and exclude NaN scores from selection. Data-driven robustness fix, valuable on every arch. (We can't build csrc locally to contribute this ourselves.)
SM12x routing: until (1) lands, route SM12x prefill top-k through a torch.topk implementation of the kernel's documented contract — the decode path already excludes SM12x from cooperative_topk. PR incoming; verified on the affected hardware that the previously 9×-reproducible crash is eliminated.
The NaN logits themselves (the primary SM12x defect): DeepGEMM fp8_fp4_mqa_logits on SM120. [New Model][Nvidia] Add SM12x support for DeepSeek V4 Flash with essential fixes #41834 appears to carry the relevant fixes (e8m0→fp32 upcast, SM120 DeepGEMM fallbacks) but is unmerged; even with (1)+(2), DSv4 output quality on SM120 remains broken for >2048-token prompts until this is addressed — with NaN scores, any correct top-k selects an arbitrary candidate set.
Happy to run further diagnostics on this hardware — SM120 workstations seem rare in CI.
Environment
deepseek-ai/DeepSeek-V4-Flash,--kv-cache-dtype fp8 --block-size 256 --tokenizer-mode deepseek_v4 --reasoning-parser deepseek_v4 --trust-remote-code, OpenAI-compatible serverSymptom
DeepSeek-V4-Flash on SM120 (enabled by #43477) crashes with
CUDA error: an illegal memory access was encounteredon all TP ranks →EngineDeadError, on the first prefill batch containing a request longer than ~2048 tokens (e.g. 16 concurrent structured-output requests with 0.5–8K-token prompts; also a single ~5K-token prompt). Short prompts serve perfectly. We reproduced the crash 9 times across vLLM 0.25.1/0.26.0 and flashinfer 0.6.13/0.6.14/0.6.15.Under
CUDA_LAUNCH_BLOCKING=1, the fault is raised in the Triton kernel_compute_global_topk_indices_and_lens_kernel(vllm/models/deepseek_v4/common/ops/cache_utils.py), reached fromDeepseekV4FlashInferSM120Attention._forward_prefill(compress-ratio-4 branch).Root-cause chain (instrumented at the tensor level)
1.
fp8_fp4_mqa_logitsproduces NaN-dominated logits on SM120.Auditing the valid
[ks, ke)region of the prefill MQA logits per C4A layer on a single 4,972-token prefill: the first C4A layer is 83% NaN (2,560,388 of 3,088,855 entries; the finite remainder looks plausible, range ≈ −2…4), and every subsequent layer is 100% NaN (cascade through the model). This is presumably the SM12x scale-handling issue (cf. the e8m0→fp32 upcast in #41834).2.
top_k_per_row_prefillmishandles NaN input on its histogram path and emits uninitialized shared memory as indices.Auditing
topk_indices_bufferimmediately afterops.top_k_per_row_prefillreturns: rows whose candidate countrowLen = ke−ks ≤ topk(the short-row path) are clean (-1-padded as documented); rows withrowLen > topk(histogram path) contain garbage starting at exactly the first such row, e.g. rows 2051…4868 of a 4,869-token request at compress ratio 4 (2051/4 ≈ 513 > 512 =index_topk). Garbage row counts differ across TP ranks on identical input (1923/2151/2120/1987) — nondeterministic, consistent with uninitialized dynamic shared memory (smemOutputis never pre-initialized and the final copy loop writes alltopKslots).This reproduces in isolation, without serving (25 lines, below): with clean random logits the kernel is correct on SM120 (0 garbage rows, and
tests/kernels/test_top_k_per_row.pypasses 12/12 here); with 83%-NaN logits, ~40% of histogram-path rows contain garbage. Two distinct failure signatures:2143289344 = 0x7FC00000— a float32 NaN bit pattern reinterpreted as an int32 index;Since the repro is data-driven (NaN input) rather than SM120-specific, the kernel's NaN mishandling likely affects all architectures; SM120 is where NaN logits actually occur in practice.
3.
compute_global_topk_indices_and_lensdereferences the garbage.Its validity mask is only
local_idx >= 0, soINT32_MAX-class indices pass and it gathersblock_table[req, idx // block_size]far out of bounds → the illegal memory access that kills the engine.Behavioral confirmation
Needle-in-haystack on the same server: a prompt below the sparse threshold retrieves the needle perfectly ("The secret code word is BLUEBERRY."); the identical needle in a ~4.5K-token prompt yields output completely unrelated to the prompt (the model hallucinates arbitrary code/text — its selected KV set is effectively random). Short prompts mask defect (1) entirely because when
rowLen ≤ topkthe top-k selects all candidates and scores never matter.Suggested fixes (layered)
csrc/libtorch_stable/sampler.cu): the histogram path should never emit unwritten smem or NaN bit patterns as indices — pad under-filled output with-1like the short-row path, and exclude NaN scores from selection. Data-driven robustness fix, valuable on every arch. (We can't build csrc locally to contribute this ourselves.)torch.topkimplementation of the kernel's documented contract — the decode path already excludes SM12x fromcooperative_topk. PR incoming; verified on the affected hardware that the previously 9×-reproducible crash is eliminated.fp8_fp4_mqa_logitson SM120. [New Model][Nvidia] Add SM12x support for DeepSeek V4 Flash with essential fixes #41834 appears to carry the relevant fixes (e8m0→fp32 upcast, SM120 DeepGEMM fallbacks) but is unmerged; even with (1)+(2), DSv4 output quality on SM120 remains broken for >2048-token prompts until this is addressed — with NaN scores, any correct top-k selects an arbitrary candidate set.Happy to run further diagnostics on this hardware — SM120 workstations seem rare in CI.