Skip to content

Commit ee8c0e5

Browse files
committed
[TRTLLM-12229][fix] Fix MTP by scratch reuse rewind (NVIDIA#14403)
Source-Commit: 7a4b113 Signed-off-by: Jiagan Cheng <jiaganc@nvidia.com>
1 parent 0f1f29e commit ee8c0e5

3 files changed

Lines changed: 38 additions & 0 deletions

File tree

tensorrt_llm/_torch/attention_backend/sparse/deepseek_v4/cache_manager.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -800,6 +800,9 @@ def _add_layer(
800800

801801
scratch_reuse_config = None
802802
if self.enable_swa_scratch_reuse:
803+
# Context requests will allocate num_extra_kv_tokens tokens for spec decoding.
804+
# Cache manager should not take them into account when calculating scratch range.
805+
# Therefore set max_rewind_len to num_extra_kv_tokens.
803806
scratch_reuse_config = SwaScratchReuseConfig(max_rewind_len=self.num_extra_kv_tokens)
804807

805808
return KVCacheManagerConfigPy(

tensorrt_llm/_torch/pyexecutor/kv_cache_manager_v2.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,7 @@ def __init__(
563563
from ..speculative import get_num_extra_kv_tokens
564564

565565
self.num_extra_kv_tokens = get_num_extra_kv_tokens(spec_config)
566+
self.max_draft_len = spec_config.max_draft_len if spec_config is not None else 0
566567
self.max_total_draft_tokens = (
567568
spec_config.max_total_draft_tokens if spec_config is not None else 0
568569
)

tests/unittest/_torch/attention/sparse/deepseek_v4/test_deepseek_v4_cache_manager.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ def _create_deepseek_v4_cache_manager(
177177
tp_size: int = 1,
178178
enable_attention_dp: bool = False,
179179
enable_swa_scratch_reuse: bool = False,
180+
spec_config: object | None = None,
180181
) -> Tuple[DeepseekV4CacheManager, DeepSeekV4SparseAttentionConfig]:
181182
"""Helper to create a DeepseekV4CacheManager for testing."""
182183

@@ -224,6 +225,7 @@ def _create_deepseek_v4_cache_manager(
224225
max_num_tokens=max_batch_size * (max_input_len + 1),
225226
sparse_attn_config=sparse_attn_config,
226227
is_draft=is_draft,
228+
spec_config=spec_config,
227229
)
228230

229231
return cache_manager, sparse_attn_config
@@ -1450,6 +1452,7 @@ def test_swa_scratch_reuse_disabled_by_default_for_main_manager(self):
14501452
try:
14511453
assert not cache_manager.enable_swa_scratch_reuse
14521454
assert not cache_manager.kv_cache_manager_py_config.enable_swa_scratch_reuse
1455+
assert cache_manager.kv_cache_manager_py_config.swa_scratch_reuse is None
14531456
assert cache_manager.num_attention_op_pools == cache_manager.num_local_layers
14541457
finally:
14551458
cache_manager.shutdown()
@@ -1468,10 +1471,40 @@ def test_swa_scratch_reuse_enabled_by_config_for_main_manager(self):
14681471
try:
14691472
assert cache_manager.enable_swa_scratch_reuse
14701473
assert cache_manager.kv_cache_manager_py_config.enable_swa_scratch_reuse
1474+
assert cache_manager.kv_cache_manager_py_config.swa_scratch_reuse is not None
1475+
assert cache_manager.kv_cache_manager_py_config.swa_scratch_reuse.max_rewind_len == 0
14711476
assert cache_manager.num_attention_op_pools == cache_manager.num_local_layers
14721477
finally:
14731478
cache_manager.shutdown()
14741479

1480+
def test_swa_scratch_reuse_uses_extra_kv_tokens_for_rewind(self):
1481+
spec_config = SimpleNamespace(
1482+
max_draft_len=7,
1483+
max_total_draft_tokens=7,
1484+
spec_dec_mode=SimpleNamespace(
1485+
is_eagle3_one_model=lambda: False,
1486+
is_mtp_one_model=lambda: False,
1487+
use_one_engine=lambda: True,
1488+
),
1489+
)
1490+
cache_manager, _ = self._create_deepseek_v4_cache_manager(
1491+
tokens_per_block=self.tokens_per_block,
1492+
max_batch_size=1,
1493+
max_seq_len=1024,
1494+
compress_ratios=[1],
1495+
dtype=DataType.BF16,
1496+
compressor_dtype=DataType.FLOAT,
1497+
spec_config=spec_config,
1498+
enable_swa_scratch_reuse=True,
1499+
)
1500+
1501+
try:
1502+
scratch_reuse = cache_manager.kv_cache_manager_py_config.swa_scratch_reuse
1503+
assert scratch_reuse is not None
1504+
assert scratch_reuse.max_rewind_len == spec_config.max_draft_len - 1
1505+
finally:
1506+
cache_manager.shutdown()
1507+
14751508
def test_draft_cache_manager_disables_swa_scratch_reuse(self):
14761509
cache_manager, _ = self._create_deepseek_v4_cache_manager(
14771510
tokens_per_block=self.tokens_per_block,
@@ -1487,6 +1520,7 @@ def test_draft_cache_manager_disables_swa_scratch_reuse(self):
14871520
try:
14881521
assert not cache_manager.enable_swa_scratch_reuse
14891522
assert not cache_manager.kv_cache_manager_py_config.enable_swa_scratch_reuse
1523+
assert cache_manager.kv_cache_manager_py_config.swa_scratch_reuse is None
14901524
assert cache_manager.num_attention_op_pools == cache_manager.num_local_layers
14911525
finally:
14921526
cache_manager.shutdown()

0 commit comments

Comments
 (0)