Skip to content

[https://nvbugs/6463967][fix] DeepSeek-V4 one-model MTP separate draft kv cache (TEP) - #16887

Open
nvxuanyuc wants to merge 1 commit into
NVIDIA:mainfrom
nvxuanyuc:dsv4aggfix
Open

[https://nvbugs/6463967][fix] DeepSeek-V4 one-model MTP separate draft kv cache (TEP)#16887
nvxuanyuc wants to merge 1 commit into
NVIDIA:mainfrom
nvxuanyuc:dsv4aggfix

Conversation

@nvxuanyuc

@nvxuanyuc nvxuanyuc commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds separate draft KV-cache support for DeepSeek-V4 sparse attention during one-model MTP under TEP.

  • Adds draft cache managers, sliding block tables, and pool base pointers for SWA-only draft layers.
  • Adds target-state and draft-state handling for eager execution and CUDA graph replay.
  • Adds generic draft execution lifecycle hooks to attention metadata.
  • Disables separate draft KV-cache allocation when PP > 1.
  • Adds GSM8K accuracy coverage and registers it in l0_dgx_b200.yml.
  • Scope is limited to SWA-only draft layers, PP=1, and beam_width=1.
  • Addresses NVBug 6463967.

Dev Engineer Review

  • Target and draft KV-cache state uses backend lifecycle hooks for preparation and restoration.
  • Unsupported configurations raise NotImplementedError.
  • The DeepSeek-V4 PP > 1 fallback prevents unsupported cache allocation.
  • The GSM8K reference includes the FP8 KV-cache and MTP qualifiers.
  • CI succeeded on the third run for 797c4a5 and the fourth run for e56cedb.

Verdict: sufficient

QA Engineer Review

Added test function:

  • TestDeepSeekV4Flash::test_tep_mtp_separate_draft_kv_cache
    • Uses GSM8K.
    • Covers TEP-style attention, MTP, CUDA graph padding, and FP8 KV cache.
    • Skips MPI world sizes below 4.

Coverage:

  • Registered in tests/integration/test_lists/test-db/l0_dgx_b200.yml.
  • The test-list entry uses a 60-second timeout.

Verdict: sufficient

Description

Wires DeepSeek-V4's sparse attention forward to the existing separate draft KV cache mechanism
for one-model MTP under TEP.

Design

  • A dedicated DeepseekV4CacheManager holds the MTP draft layers; the metadata carries
    draft-sized sliding block tables + draft pool base pointers, allocated separately.
  • The draft's _num_tables and precomputed sliding tables are populated in prepare() via
    draft_mgr.compute_sliding_block_tables(...), mirroring the target manager.
  • Target/draft state is swapped via save/apply/restore_target_sparse_state at both the
    eager draft_kv_cache_context and the CUDA-graph prepare_attn_metadata_for_draft_replay,
    gated by isinstance(attn_metadata, DeepseekV4TrtllmAttentionMetadata) (mirrors the DSA
    branch). The swap is a pointer rebind plus per-batch copy.
  • Scope: SWA-only draft layers (compress_ratio 1, asserted); PP=1 only (folds otherwise);
    beam_width=1 (pre-existing DSv4 + MTP constraint).

Validation Results

[DeepSeek-V4-Flash | TEP4 | fp8kv]

Separate vs unified draft KV

max_draft_len AL (separate) AL (unified) GSM8K (separate) GSM8K (unified)
1 1.9600 1.9591 95.41 94.84
2 2.6418 2.6499 95.03 94.88

Perf [nextn=1 | ISL/OSL 2k/2k | max conc 64]

metric separate unified overhead%
BS1 ITL (ms) 3.556 3.561 -0.15%
Throughput (tok/s) 5787.4 5692.9 -1.66%
AL-normalized throughput (tok/s / avg AL) 2919.5 2890.9 -0.99%

Test Coverage

TestDeepSeekV4Flash::test_tep_mtp_separate_draft_kv_cache (GSM8K), registered in
l0_dgx_b200.yml. Local run: 95.53.

GitHub Bot Help

To see a list of available CI bot commands, please comment /bot help.

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

DeepSeek-V4 sparse attention now supports separate draft KV-cache buffers for one-model MTP. Backend hooks manage draft forward and replay state. Cache selection and integration coverage are updated.

Changes

DeepSeek-V4 draft KV-cache support

Layer / File(s) Summary
Draft replay hook contract
tensorrt_llm/_torch/attention_backend/trtllm.py, tensorrt_llm/_torch/attention_backend/sparse/dsa.py
Attention metadata defines draft replay and forward hooks. DSA metadata saves, updates, and restores indexer offsets and slot mappings.
Draft sparse buffer setup
tensorrt_llm/_torch/attention_backend/sparse/deepseek_v4/deepseek_v4.py
DeepSeek-V4 metadata builds shared target and draft pointer mappings, allocates draft buffers, validates draft layers, and prepares draft sliding-window tables.
Draft state replay and restoration
tensorrt_llm/_torch/attention_backend/sparse/deepseek_v4/deepseek_v4.py, tensorrt_llm/_torch/speculative/interface.py
Speculative replay and draft-forward contexts apply backend-specific draft state and restore target state after completion or failure.
Cache policy and integration coverage
tensorrt_llm/_torch/pyexecutor/_util.py, tests/integration/defs/accuracy/..., tests/integration/test_lists/test-db/l0_dgx_b200.yml, tests/unittest/_torch/attention/sparse/dsa/test_dsa_indexer.py
Separate draft cache creation is disabled for DeepSeek-V4 with pipeline parallelism greater than one. TEP MTP FP8 accuracy coverage and hook assertions are added.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant SpeculativeInterface
  participant DeepseekV4TrtllmAttentionMetadata
  participant DSAtrtllmAttentionMetadata
  SpeculativeInterface->>DeepseekV4TrtllmAttentionMetadata: prepare draft forward or replay
  DeepseekV4TrtllmAttentionMetadata->>DSAtrtllmAttentionMetadata: prepare DSA replay state
  SpeculativeInterface->>DeepseekV4TrtllmAttentionMetadata: restore backend state
  DeepseekV4TrtllmAttentionMetadata->>DSAtrtllmAttentionMetadata: restore DSA replay state
Loading

Suggested reviewers: qijune, schetlur-nv, bowenfu

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 69.57% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description check ✅ Passed The description explains the change, design, scope, validation results, and test coverage, but it omits the PR Checklist section.
Title check ✅ Passed The title follows the required ticket/type format and clearly identifies the DeepSeek-V4 one-model MTP separate draft KV-cache fix.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tensorrt_llm/_torch/attention_backend/sparse/deepseek_v4/cache_manager.py`:
- Around line 603-606: Modernize the annotations at all three sites: in
tensorrt_llm/_torch/attention_backend/sparse/deepseek_v4/cache_manager.py:603-606,
change the per_layer_compress_ratios property return type to list[int]; in
tensorrt_llm/_torch/attention_backend/sparse/deepseek_v4/deepseek_v4.py:653-761,
annotate helper parameters and returns, using None for mutating helpers and the
precise snapshot type for snapshot-returning helpers; in
tests/integration/defs/accuracy/test_llm_api_pytorch.py:3880, add -> None to the
test method.

In `@tensorrt_llm/_torch/speculative/interface.py`:
- Around line 196-204: Make the DeepseekV4TrtllmAttentionMetadata mutation in
prepare_attn_metadata_for_draft_replay exception-safe by wrapping
apply_draft_sparse_state() with restoration of the saved sparse state when it
raises. Restore the saved metadata before re-raising the original exception,
while preserving the existing saved-state behavior on success.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 78af6d9d-93bc-409f-919e-60efd609be8d

📥 Commits

Reviewing files that changed from the base of the PR and between 49e16c9 and 1c9fb3a.

📒 Files selected for processing (7)
  • tensorrt_llm/_torch/attention_backend/sparse/deepseek_v4/cache_manager.py
  • tensorrt_llm/_torch/attention_backend/sparse/deepseek_v4/deepseek_v4.py
  • tensorrt_llm/_torch/pyexecutor/_util.py
  • tensorrt_llm/_torch/speculative/interface.py
  • tests/integration/defs/accuracy/references/gsm8k.yaml
  • tests/integration/defs/accuracy/test_llm_api_pytorch.py
  • tests/integration/test_lists/test-db/l0_dgx_b200.yml

Comment on lines +603 to +606
@property
def per_layer_compress_ratios(self) -> List[int]:
"""Per-layer compress ratios (MTP-extended), indexed by global layer."""
return self._compress_ratios

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add the required modern type annotations.

  • tensorrt_llm/_torch/attention_backend/sparse/deepseek_v4/cache_manager.py#L603-L606: use list[int] instead of List[int].
  • tensorrt_llm/_torch/attention_backend/sparse/deepseek_v4/deepseek_v4.py#L653-L761: annotate helper arguments and return types; use None for mutating helpers and a precise snapshot type.
  • tests/integration/defs/accuracy/test_llm_api_pytorch.py#L3880-L3880: annotate the test method with -> None.
📍 Affects 3 files
  • tensorrt_llm/_torch/attention_backend/sparse/deepseek_v4/cache_manager.py#L603-L606 (this comment)
  • tensorrt_llm/_torch/attention_backend/sparse/deepseek_v4/deepseek_v4.py#L653-L761
  • tests/integration/defs/accuracy/test_llm_api_pytorch.py#L3880-L3880
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tensorrt_llm/_torch/attention_backend/sparse/deepseek_v4/cache_manager.py`
around lines 603 - 606, Modernize the annotations at all three sites: in
tensorrt_llm/_torch/attention_backend/sparse/deepseek_v4/cache_manager.py:603-606,
change the per_layer_compress_ratios property return type to list[int]; in
tensorrt_llm/_torch/attention_backend/sparse/deepseek_v4/deepseek_v4.py:653-761,
annotate helper parameters and returns, using None for mutating helpers and the
precise snapshot type for snapshot-returning helpers; in
tests/integration/defs/accuracy/test_llm_api_pytorch.py:3880, add -> None to the
test method.

Source: Coding guidelines

Comment thread tensorrt_llm/_torch/speculative/interface.py Outdated
@nvxuanyuc

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #62069 [ run ] triggered by Bot. Commit: 797c4a5 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #62069 [ run ] completed with state FAILURE. Commit: 797c4a5
/LLM/main/L0_MergeRequest_PR pipeline #50254 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@nvxuanyuc

Copy link
Copy Markdown
Collaborator Author

/bot run

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #62256 [ run ] triggered by Bot. Commit: 797c4a5 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #62256 [ run ] completed with state FAILURE. Commit: 797c4a5
/LLM/main/L0_MergeRequest_PR pipeline #50425 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@nvxuanyuc

Copy link
Copy Markdown
Collaborator Author

/bot run

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63580 [ run ] triggered by Bot. Commit: e56cedb Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63580 [ run ] completed with state FAILURE. Commit: e56cedb
/LLM/main/L0_MergeRequest_PR pipeline #51544 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@nvxuanyuc

Copy link
Copy Markdown
Collaborator Author

/bot run

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63597 [ run ] triggered by Bot. Commit: e56cedb Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63597 [ run ] completed with state FAILURE. Commit: e56cedb
/LLM/main/L0_MergeRequest_PR pipeline #51558 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@nvxuanyuc

Copy link
Copy Markdown
Collaborator Author

/bot run

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63783 [ run ] triggered by Bot. Commit: e56cedb Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63783 [ run ] completed with state SUCCESS. Commit: e56cedb
/LLM/main/L0_MergeRequest_PR pipeline #51730 completed with status: 'SUCCESS'

CI Report

Link to invocation

@BowenFu BowenFu left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checked the default path is untouched: prepare_attn_metadata_for_draft_replay and draft_kv_cache_context both still bail on not isinstance(attn_metadata, TrtllmAttentionMetadata), the new prepare_for_draft_replay/restore_after_draft_replay on TrtllmAttentionMetadata are no-ops, and _init_draft_sparse_buffers early-returns without a separate draft manager. The DSA block moved out of speculative/interface.py is byte-equivalent apart from the saved_dsa_state -> saved_backend_state["dsa"] key, which has no other reader. Confirmed the two entry points can't nest (the model_engine wrapper only surrounds cuda_graph_runner.replay, which doesn't re-run the mtp.py context manager), so save_target_sparse_state can't snapshot draft pointers as target.

Not blocking, for a follow-up: draft_kv_cache_context reaches the DSV4 sparse hooks via hasattr(attn_metadata, "save_target_sparse_state") while this same PR introduces proper base-class virtuals for the neighbouring prepare_for_draft_replay — worth making the sparse-state pair virtual too. Also _init_draft_sparse_buffers infers the draft layer's ratio from the target's compress_ratios[-1] and raises NotImplementedError from __post_init__; an explicit draft-side ratio would be less implicit.

The one open thread is CodeRabbit's List[int] -> list[int] annotation nit on an outdated diff — style only, not blocking.

@nvpohanh

nvpohanh commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

[by Codex] @liji-nv Could you please review PR #16887 for the KV-cache manager changes? Thanks!

@pengbowang-nv pengbowang-nv left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left some questions.

Comment thread tensorrt_llm/_torch/attention_backend/trtllm.py Outdated
self.draft_swa_buffer_ptrs = None
self.draft_compressed_buffer_ptrs = None
draft_mgr = self.draft_kv_cache_manager
if draft_mgr is None or not hasattr(draft_mgr, "compute_sliding_block_tables"):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: as dsv4 is only supported by DSV4 kv cache manager, I suggest remove hasattr call here and below. Or even if we want to support more types of kvcache managers, I suggest explicitly use isinstance to confirm.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed with an explicit isinstance check. The guard is still kept because DSv4 can use a non-DSv4 draft manager with other speculative-decoding methods such as EAGLE3.


# DeepSeek-V4: repoint SWA/compress tables and pool pointers to the draft.
if hasattr(attn_metadata, "save_target_sparse_state"):
saved_dsv4_state = attn_metadata.save_target_sparse_state()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if it is possible to use our new interface, prepare_for_draft_replay and restore_after_draft_replay? If so then they are not only for replay, I suggest rename these api to prepare_for_draft_forward and restore_after_draft_forward.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed. Merged DSv4’s separate save/apply operations into one hook and renamed the pair to prepare_for_draft_forward and restore_after_draft_forward.
We retain two hook pairs because some state must be prepared during the eager (capture) path, while other state only requires refresh before graph replay. For example, DSv4’s tensor/pointer switch is needed in both paths, whereas DSA’s in-place metadata refresh is replay-specific.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
tensorrt_llm/_torch/attention_backend/trtllm.py (1)

520-533: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Document the draft-hook state contract.

State that each prepare_* result is passed unchanged to its paired restore_* method. Add Returns and Args sections for these public hooks.

Proposed documentation update
 def prepare_for_draft_replay(self) -> dict | None:
-    """Prepare all backend state required for draft CUDA graph replay."""
+    """Prepare backend state for draft CUDA graph replay.
+
+    Returns:
+        Saved backend state for `restore_after_draft_replay`, or `None`.
+    """
     return None

 def restore_after_draft_replay(self, saved_state: dict | None) -> None:
-    """Restore backend state saved for draft CUDA graph replay."""
+    """Restore backend state after draft CUDA graph replay.
+
+    Args:
+        saved_state: State returned by `prepare_for_draft_replay`.
+    """

As per coding guidelines, “Use docstrings rather than comments for externally usable interfaces, Google-style docstrings for classes and functions.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tensorrt_llm/_torch/attention_backend/trtllm.py` around lines 520 - 533,
Update the docstrings for prepare_for_draft_replay, restore_after_draft_replay,
prepare_for_draft_forward, and restore_after_draft_forward to use Google-style
Returns and Args sections, documenting that each prepare method’s result is
passed unchanged to its paired restore method and describing the saved_state
argument and return values.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/unittest/_torch/attention/sparse/dsa/test_dsa_indexer.py`:
- Line 3293: Extend
TestPrepareRestoreAttnMetadataForDraftReplay.test_prepare_swaps_and_restore_recovers
beyond the None case by configuring a nested non-None draft-replay state and
asserting it is propagated during prepare and restored afterward. Preserve the
existing None coverage and add the test to the appropriate coverage listing if
required by the repository’s test tracking.

---

Nitpick comments:
In `@tensorrt_llm/_torch/attention_backend/trtllm.py`:
- Around line 520-533: Update the docstrings for prepare_for_draft_replay,
restore_after_draft_replay, prepare_for_draft_forward, and
restore_after_draft_forward to use Google-style Returns and Args sections,
documenting that each prepare method’s result is passed unchanged to its paired
restore method and describing the saved_state argument and return values.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 04e953a5-9e7d-426e-b697-d75fc0e231bb

📥 Commits

Reviewing files that changed from the base of the PR and between 36922c7 and a9e086a.

📒 Files selected for processing (9)
  • tensorrt_llm/_torch/attention_backend/sparse/deepseek_v4/deepseek_v4.py
  • tensorrt_llm/_torch/attention_backend/sparse/dsa.py
  • tensorrt_llm/_torch/attention_backend/trtllm.py
  • tensorrt_llm/_torch/pyexecutor/_util.py
  • tensorrt_llm/_torch/speculative/interface.py
  • tests/integration/defs/accuracy/references/gsm8k.yaml
  • tests/integration/defs/accuracy/test_llm_api_pytorch.py
  • tests/integration/test_lists/test-db/l0_dgx_b200.yml
  • tests/unittest/_torch/attention/sparse/dsa/test_dsa_indexer.py
🚧 Files skipped from review as they are similar to previous changes (6)
  • tensorrt_llm/_torch/pyexecutor/_util.py
  • tests/integration/test_lists/test-db/l0_dgx_b200.yml
  • tensorrt_llm/_torch/attention_backend/sparse/dsa.py
  • tests/integration/defs/accuracy/references/gsm8k.yaml
  • tensorrt_llm/_torch/attention_backend/sparse/deepseek_v4/deepseek_v4.py
  • tests/integration/defs/accuracy/test_llm_api_pytorch.py

Comment thread tests/unittest/_torch/attention/sparse/dsa/test_dsa_indexer.py
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tensorrt_llm/_torch/attention_backend/sparse/dsa.py`:
- Around line 726-789: Add Google-style docstrings to prepare_for_draft_replay
and restore_after_draft_replay documenting their speculative replay contract:
explain when prepare_for_draft_replay returns None, identify the saved-state
contents, and describe the buffers it updates; document that
restore_after_draft_replay does nothing for None and restores each saved buffer
state. Replace the existing explanatory inline comments only where the new
docstrings cover the same interface behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 2a81b552-d1fa-4341-8baf-f578fac8ebec

📥 Commits

Reviewing files that changed from the base of the PR and between e1a952a and 0a7bf65.

📒 Files selected for processing (9)
  • tensorrt_llm/_torch/attention_backend/sparse/deepseek_v4/deepseek_v4.py
  • tensorrt_llm/_torch/attention_backend/sparse/dsa.py
  • tensorrt_llm/_torch/attention_backend/trtllm.py
  • tensorrt_llm/_torch/pyexecutor/_util.py
  • tensorrt_llm/_torch/speculative/interface.py
  • tests/integration/defs/accuracy/references/gsm8k.yaml
  • tests/integration/defs/accuracy/test_llm_api_pytorch.py
  • tests/integration/test_lists/test-db/l0_dgx_b200.yml
  • tests/unittest/_torch/attention/sparse/dsa/test_dsa_indexer.py
🚧 Files skipped from review as they are similar to previous changes (8)
  • tensorrt_llm/_torch/pyexecutor/_util.py
  • tests/integration/defs/accuracy/test_llm_api_pytorch.py
  • tests/integration/test_lists/test-db/l0_dgx_b200.yml
  • tensorrt_llm/_torch/attention_backend/trtllm.py
  • tests/unittest/_torch/attention/sparse/dsa/test_dsa_indexer.py
  • tensorrt_llm/_torch/speculative/interface.py
  • tests/integration/defs/accuracy/references/gsm8k.yaml
  • tensorrt_llm/_torch/attention_backend/sparse/deepseek_v4/deepseek_v4.py

Comment on lines +726 to +789
def prepare_for_draft_replay(self) -> dict | None:
if (self.kv_cache_manager is None
or not hasattr(self.kv_cache_manager, "index_head_dim")):
return None

saved = {
"host_indexer_k_cache_block_offsets":
self.host_indexer_k_cache_block_offsets.clone(),
"indexer_k_cache_block_offsets":
self.indexer_k_cache_block_offsets.clone(),
"host_slot_mapping_fp8":
self.host_slot_mapping_fp8.clone(),
"host_slot_mapping_scale":
self.host_slot_mapping_scale.clone(),
"slot_mapping_fp8":
self.slot_mapping_fp8.clone(),
"slot_mapping_scale":
self.slot_mapping_scale.clone(),
}

# Derive pool indices from the draft manager's encoded block
# offsets (via _get_pool_block_indices) instead of using raw block
# IDs. With host cache offload, block IDs can exceed
# blocks_in_primary_pool after offload swaps (the block keeps its
# original high ID even though its memory now lives in the primary
# GPU pool). Using raw block IDs as pool indices causes OOB access
# in the indexer k-cache buffers. _get_pool_block_indices correctly
# decodes memPoolBlockIndex from the C++ encoded offsets.
# Note: kv_cache_manager was already swapped to draft above
# in prepare_attn_metadata_for_draft_replay() in _torch/speculative/interface.py
pool_indices = self._get_pool_block_indices()
num_blocks = pool_indices.shape[1]
self.host_indexer_k_cache_block_offsets[:self.num_seqs, :
num_blocks].copy_(pool_indices)
self.indexer_k_cache_block_offsets[:self.num_seqs].copy_(
self.host_indexer_k_cache_block_offsets[:self.num_seqs],
non_blocking=True,
)
# Safety clamp: sanitize stale padding entries beyond num_seqs
# that may contain negative or out-of-range values, matching the
# regular DSA prepare() flow.
self.indexer_k_cache_block_offsets.clamp_(min=0)
Indexer.recompute_slot_mappings(self)

return saved

def restore_after_draft_replay(self, saved_state: dict | None) -> None:
if saved_state is None:
return

self.host_indexer_k_cache_block_offsets.copy_(
saved_state["host_indexer_k_cache_block_offsets"],
non_blocking=True,
)
self.indexer_k_cache_block_offsets.copy_(
saved_state["indexer_k_cache_block_offsets"],
non_blocking=True,
)
self.host_slot_mapping_fp8.copy_(saved_state["host_slot_mapping_fp8"])
self.host_slot_mapping_scale.copy_(
saved_state["host_slot_mapping_scale"])
self.slot_mapping_fp8.copy_(saved_state["slot_mapping_fp8"])
self.slot_mapping_scale.copy_(saved_state["slot_mapping_scale"])

@coderabbitai coderabbitai Bot Aug 7, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Document the draft replay hook contract.

prepare_for_draft_replay() and restore_after_draft_replay() are called by the speculative replay interface. Add Google-style docstrings. Define the None behavior, saved-state contents, and the buffers that each method changes or restores.

As per coding guidelines, “Use docstrings rather than comments for externally usable interfaces, Google-style docstrings for classes and functions.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tensorrt_llm/_torch/attention_backend/sparse/dsa.py` around lines 726 - 789,
Add Google-style docstrings to prepare_for_draft_replay and
restore_after_draft_replay documenting their speculative replay contract:
explain when prepare_for_draft_replay returns None, identify the saved-state
contents, and describe the buffers it updates; document that
restore_after_draft_replay does nothing for None and restores each saved buffer
state. Replace the existing explanatory inline comments only where the new
docstrings cover the same interface behavior.

Source: Coding guidelines

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hook contract and None behavior are already documented on the base methods in TrtllmAttentionMetadata. These overrides follow that contract, while the existing inline comments document the DSA-specific mutation details and rationale. Repeating the contract here would be redundant, so I’d prefer to keep the documentation at the interface level.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

base_file=$(fd -a '^trtllm\.py$' tensorrt_llm/_torch/attention_backend | head -n 1)
if [[ -z "${base_file}" ]]; then
  echo "Could not locate trtllm.py"
  exit 1
fi

ast-grep outline "$base_file" --items all --match 'TrtllmAttentionMetadata|prepare_for_draft_replay|restore_after_draft_replay'
rg -n -A18 -B4 \
  'def prepare_for_draft_replay\(|def restore_after_draft_replay\(' \
  "$base_file"

Length of output: 4606


@nvxuanyuc, I need to correct my previous reply.

The base methods have short docstrings, but they do not define the None behavior, saved-state contents, or DSA buffer mutations. The shell result shows only the general replay lifecycle descriptions.

Therefore, the original documentation concern remains valid. I understand your preference to keep the interface documentation centralized. If that is the intended project convention, the maintainers can choose not to add override docstrings.

You are interacting with an AI system.

@nvxuanyuc

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #64453 [ run ] triggered by Bot. Commit: 0a7bf65 Link to invocation

@nvxuanyuc

Copy link
Copy Markdown
Collaborator Author

@BowenFu Thanks for the review. draft_kv_cache_context now uses the virtual prepare_for_draft_forward/restore_after_draft_forward hooks instead of hasattr. I kept deriving the ratio from the existing compress_ratios list because it is used only for the future-facing guard against non-SWA MTP layers; current DSv4 variants should not trigger it. The CodeRabbit style comment has also been addressed.

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #64453 [ run ] completed with state FAILURE. Commit: 0a7bf65
/LLM/main/L0_MergeRequest_PR pipeline #52328 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

…t kv cache (TEP)

Signed-off-by: Xuanyu Chen <xuanyuc@nvidia.com>
@nvxuanyuc

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #64723 [ run ] triggered by Bot. Commit: 63c1e8f Link to invocation

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants