Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .lil/changes/vllm-822.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"schema": "local-inference-release-change/v1",
"id": "vllm-822",
"category": "fix",
"summary": "Keep long GLM DCP profile prefills out of bounded KDA decode",
"models": ["GLM-5.3-Flash"],
"compatibility": "No configuration change is required. Valid MTP decode rows retain the B12X KDA decode path.",
"details": [
"A row enters speculative KDA decode only when its length is one target token plus its declared draft count.",
"This prevents a zero-draft marker on a long memory-profile prefill from exceeding the decode kernel capacity during TP4/DCP4 startup."
],
"pull_requests": [822],
"authors": ["Local Inference Lab"],
"evidence": ["https://github.com/local-inference-lab/vllm/pull/822"],
"requires": []
}
39 changes: 39 additions & 0 deletions tests/v1/attention/test_gdn_metadata_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
)
from vllm.config import SpeculativeConfig
from vllm.config.compilation import CUDAGraphMode
from vllm.v1.attention.backends.b12x_gdn_metadata import B12xGdnMixedMetadata
from vllm.v1.attention.backends.gdn_attn import (
GDNAttentionMetadata,
GDNAttentionMetadataBuilder,
Expand Down Expand Up @@ -174,6 +175,26 @@ class GDNBuildTestCase:
expected_num_prefill_tokens=0,
expected_num_spec_decodes=0,
),
"long_prefill_with_zero_draft_profile_marker": GDNBuildTestCase(
seq_lens=[4112],
query_lens=[4096],
num_decode_draft_tokens=[0],
num_speculative_tokens=3,
expected_num_decodes=0,
expected_num_prefills=1,
expected_num_prefill_tokens=4096,
expected_num_spec_decodes=0,
),
"single_token_zero_draft_decode": GDNBuildTestCase(
seq_lens=[33],
query_lens=[1],
num_decode_draft_tokens=[0],
num_speculative_tokens=3,
expected_num_decodes=1,
expected_num_prefills=0,
expected_num_prefill_tokens=0,
expected_num_spec_decodes=0,
),
# Multi-token prefill alongside spec decode — no decode to reclassify
"spec_decode_with_real_prefill": GDNBuildTestCase(
seq_lens=[100, 20],
Expand Down Expand Up @@ -442,6 +463,24 @@ def test_gdn_build_classification(test_case: GDNBuildTestCase):
assert meta.num_spec_decodes == test_case.expected_num_spec_decodes


def test_b12x_mixed_metadata_keeps_zero_draft_profile_in_prefill() -> None:
builder = _create_gdn_builder(num_speculative_tokens=3)
builder._b12x_mixed = B12xGdnMixedMetadata(
max_tokens=4096, max_seqs=1, state_columns=4, device=DEVICE
)
metadata = _build(
builder,
BatchSpec(seq_lens=[4112], query_lens=[4096]),
num_decode_draft_tokens=[0],
)

assert metadata.num_prefills == 1
assert metadata.num_spec_decodes == 0
assert metadata.b12x_mixed is not None
assert metadata.b12x_mixed._num_non_spec == 1
assert metadata.b12x_mixed._num_spec == 0


def test_fresh_single_token_prompt_uses_prefill_state_initialization() -> None:
builder = _create_gdn_builder()
batch = BatchSpec(seq_lens=[1], query_lens=[1])
Expand Down
6 changes: 5 additions & 1 deletion vllm/v1/attention/backends/b12x_gdn_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,11 @@ def stage(
for row, (start, end) in enumerate(zip(starts, starts[1:])):
if end == start:
continue
if drafts is not None and drafts[row] >= 0 and end - start > 1:
if (
drafts is not None
and drafts[row] >= 0
and end - start == drafts[row] + 1
):
if end - start > self.state_columns:
raise ValueError("GDN verification exceeds planned state columns")
spec_rows.append(row)
Expand Down
10 changes: 9 additions & 1 deletion vllm/v1/attention/backends/gdn_attn.py
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,15 @@ def build( # type: ignore[override]
spec_sequence_masks = None
num_spec_decodes = 0
else:
spec_sequence_masks_cpu = num_decode_draft_tokens_cpu >= 0
# A speculative row contains exactly one target token followed by
# its draft tokens. Profiling may provide a zero-draft marker for
# a long prefill, which must not enter the bounded decode kernel.
query_lens_cpu = query_start_loc_cpu.diff()
spec_sequence_masks_cpu = (
(num_decode_draft_tokens_cpu >= 0)
& (num_decode_draft_tokens_cpu <= self.num_spec)
& (query_lens_cpu == num_decode_draft_tokens_cpu + 1)
)
num_spec_decodes = spec_sequence_masks_cpu.sum().item()
# A zero-draft varlen batch still recovers the previous step's
# accepted recurrent state before consuming its bonus tokens.
Expand Down