Skip to content

[None][feat] Add DSA sparse attention reference to VanillaAttention and unify sparse backend tests - #16309

Open
yihwang-nv wants to merge 19 commits into
NVIDIA:mainfrom
yihwang-nv:vanilla-dsa-attention
Open

[None][feat] Add DSA sparse attention reference to VanillaAttention and unify sparse backend tests#16309
yihwang-nv wants to merge 19 commits into
NVIDIA:mainfrom
yihwang-nv:vanilla-dsa-attention

Conversation

@yihwang-nv

@yihwang-nv yihwang-nv commented Jul 13, 2026

Copy link
Copy Markdown
Collaborator

Dev Engineer Review

  • Added DSA sparse attention support to VanillaAttention.
  • Added sparse MLA execution with top-k validation, paged latent KV reconstruction, selected-KV gathering, FP32 softmax, and causal checks.
  • Registered VanillaAttention for the dsa sparse algorithm.
  • Updated sparse backend capability detection and TRTLLM SM-version restrictions.
  • Updated the RocketKV comment without changing runtime behavior.
  • Unified sparse test configuration and backend execution through SparseAttentionConfig.
  • Added sparse cache construction, selection generation, oracle comparison, and sparse tolerances.
  • Consolidated DSA model configuration into deepseekv3_2_dsa_mla.
  • Review focus: validate sparse index bounds, padding, causal constraints, cache layouts, dtype reinterpretation, fallback behavior, and context or generation MLA regressions.
  • No public API or dependency changes are reported.

QA Engineer Review

Modified test code

  • Modified tests/unittest/_torch/attention/sparse/dsa/test_dsa_sparse_mla.py.
    • Replaced explicit reference calculations with VanillaAttention golden-output comparison.
    • Added deterministic input and sparse top-k generation.
    • Added context and generation phase output collection.
    • Updated backend-specific RoPE and sparse-parameter handling.
  • Modified tests/unittest/_torch/attention/test_attention_backends.py.
    • Added sparse context, generation, and mixed-phase cases.
    • Added sparse top-k-based phase lengths.
  • Modified sparse test harness code in backend_case.py, backend_capability.py, and model_attn_config.py.

Test-list coverage

  • No changes to tests/integration/test_lists/, test-db/, or qa/ are reported.
  • CI coverage for the modified test functions requires verification.

Verdict: needs follow-up.

Description

Integrate DSA (DeepSeek Sparse Attention) into the VanillaAttention reference backend and express sparse-attention tests through the unified model-driven backend harness, so a sparse algorithm plugs into Vanilla the same way it does into TRTLLM. Vanilla is intended as the reference platform for the planned TRTLLM sparse refactor.

  1. Vanilla DSA attention-over-selection (vanilla.py). Backend-neutral sparse_kv_predict / sparse_attn_predict hooks matching the production contract (results written into forward_args.sparse_prediction), plus the _mla_forward_sparse golden: applies MLA RoPE, appends and reconstructs paged latent KV across context and generation, validates top-k shape/dtype/padding/bounds/causality before mutating the cache, gathers selected latent K/V, and evaluates absorbed MLA with an FP32 softmax.

  2. Unified sparse test harness (backend_case.py, model_attn_config.py, backend_capability.py, test_attention_backends.py). A sparse workload is an ordinary ModelAttnConfig (deepseekv3_2_dsa_mla) sitting next to the dense MLA configs. It carries the real user-facing sparse_attention_config — lowered via the production to_sparse_params / to_sparse_metadata_params / sparse KV-cache manager — plus a backend-neutral SparseHarnessConfig. The runner injects deterministic causal selections and compares every supported backend against the Vanilla golden. This replaces the standalone DSA test files.

  3. VanillaIndexer (vanilla.py). An FP32 reference for the production DSA / DeepSeek-V4 Indexer, wrapping a production indexer instance so it runs against that indexer's own weights. It is a standalone reference (not wired into forward), and test_sparse_mla_forward.py now builds its DeepSeek-V4 reference top-k on it, removing the duplicated projection / scoring / top-k helpers.

  4. Block-selection scaffold (backend_case.py). A reusable causal block-index builder plus validation and dispatch stubs for the future selection_unit="block" family (e.g. RocketKV); inert until a block config lands.

Scope is limited to the internal Vanilla backend and sparse tests. The DSA indexer stays external, the production backend remains DSATrtllmAttention, and no other sparse algorithm or public API is changed. The explicit Vanilla paths are correctness oracles, not performance paths.

Test Coverage

Verified on a Blackwell GPU (sm 100), where the TRTLLM DSA path runs and is compared against the Vanilla golden:

  • pytest tests/unittest/_torch/attention/test_attention_backends.py -k dsa → 6 passed (deepseekv3_2_dsa_mla × {ctx, gen, mix} × {random, singleton}).
  • pytest tests/unittest/_torch/attention/sparse/test_sparse_mla_forward.py -k "deepseek_v4 and auto and (small_prefill or small_decode or small_mixed)" → passed (DeepSeek-V4 indexer reference now driven by VanillaIndexer).
  • py_compile and import checks pass.

On sm < 100, TRTLLM DSA is skipped and only the Vanilla golden (plus its analytic singleton oracle) runs.

PR Checklist

  • PR description clearly explains what and why.
  • PR follows the TensorRT-LLM coding guidelines to the best of my knowledge.
  • Test cases cover the new code path.
  • No public API change or new dependency is introduced.
  • CODEOWNERS and the architecture diagram do not require updates.

GitHub Bot Help

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

Signed-off-by: Yihan Wang <yihwang@nvidia.com>
Signed-off-by: Yihan Wang <yihwang@nvidia.com>
@yihwang-nv
yihwang-nv requested a review from wenmingw July 15, 2026 06:13
@yihwang-nv

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@yihwang-nv yihwang-nv changed the title [None][feat] Add DSA sparse attention to VanillaAttention [None][feat] Add DSA sparse attention + indexer reference to VanillaAttention; unify sparse backend tests Jul 15, 2026
@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #59376 [ run ] triggered by Bot. Commit: b3238f5 Link to invocation

# (production replays a captured decode graph); it must still match the
# eager golden.
if case.is_gen_only:
if case.is_gen_only and not case.is_sparse:

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.

Why we cannot enable cuda graph for sparse case?

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.

This backend-only path is an eager correctness oracle: the standalone sparse runner validates the injected request-local selections on the host and rebuilds each request's logical cache with Python loops, neither of which is graph-capturable. Capturing would require rewriting the runner into a static-buffer form that no longer matches its role. Graph coverage of the DSA decode kernel is exercised at the model level, not by this backend oracle. I added a code comment making the exclusion explicit; happy to file a follow-up if you'd like graph coverage added here.

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.

Please add a TODO here, let's try to add it in a follow-up PR

Comment thread tests/unittest/_torch/attention/backend_case.py Outdated
Comment thread tests/unittest/_torch/attention/backend_case.py Outdated
Comment thread tests/unittest/_torch/attention/model_attn_config.py Outdated
@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #59376 [ run ] completed with state SUCCESS. Commit: b3238f5
/LLM/main/L0_MergeRequest_PR pipeline #47850 completed with status: 'SUCCESS'

CI Report

Link to invocation

- Register DSA in the vanilla sparse-backend factory so VanillaAttention is
  built through create_attention like every other backend (no special-casing
  in the sparse runner); update_quant_config is now called unconditionally.
- Derive sparse family / selection unit / top-k from is_mla and
  sparse_attention_config, and move the model-agnostic sweep dimensions to
  shared constants, so ModelAttnConfig no longer carries a SparseHarnessConfig
  or hf_config_overrides/atol/rtol. Sparse tolerance is derived in _tolerances.
- Clarify why the backend-only sparse oracle skips the captured-CUDA-graph path.

Signed-off-by: Yihan Wang <yihwang@nvidia.com>
@yihwang-nv

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #59435 [ run ] triggered by Bot. Commit: 108df3f Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #59435 [ run ] completed with state SUCCESS. Commit: 108df3f
/LLM/main/L0_MergeRequest_PR pipeline #47904 completed with status: 'SUCCESS'
Pipeline passed with automatic retried tests. Check the rerun report for details.

CI Report

Link to invocation

@yihwang-nv
yihwang-nv marked this pull request as ready for review July 15, 2026 15:05
@yihwang-nv
yihwang-nv requested a review from a team as a code owner July 15, 2026 15:06
@yihwang-nv
yihwang-nv requested review from PerkzZheng and yunruis July 15, 2026 15:06
@coderabbitai

coderabbitai Bot commented Jul 15, 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

VanillaAttention now supports DSA sparse MLA with paged latent-cache handling, sparse selection routing, selected-token attention, and contiguous cache writes. The attention test harness adds sparse configuration, cache execution, deterministic inputs, capability checks, and Vanilla-versus-TRTLLM comparisons.

Changes

DSA sparse MLA support

Layer / File(s) Summary
Sparse configuration and sweep generation
tests/unittest/_torch/attention/model_attn_config.py, tests/unittest/_torch/attention/backend_capability.py, tests/unittest/_torch/attention/test_attention_backends.py
The harness defines DSA sparse configuration, enables Vanilla sparse capability, validates TRTLLM hardware requirements, and generates sparse context, generation, and mixed cases.
Vanilla sparse MLA execution
tensorrt_llm/_torch/attention_backend/vanilla.py, tensorrt_llm/_torch/attention_backend/sparse/registry.py, tensorrt_llm/_torch/pyexecutor/py_executor_creator.py
VanillaAttention materializes NHD or HND latent caches, validates sparse inputs, performs selected-token attention, routes DSA sparse requests, and uses contiguous dtype-reinterpreted cache copies. The registry dispatches DSA to VanillaAttention.
Sparse backend harness execution
tests/unittest/_torch/attention/backend_case.py
BackendCase generates causal selections and sparse MLA inputs, builds sparse cache managers, runs context and generation phases, checks cache updates and singleton outputs, applies sparse tolerances, and skips sparse CUDA-graph replay.
Sparse golden comparison tests
tests/unittest/_torch/attention/sparse/dsa/test_dsa_sparse_mla.py
The DSA test runs VanillaAttention and TRTLLM with deterministic selections, applies backend-specific RoPE and metadata handling, and compares phase and layer outputs.

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

Sequence Diagram(s)

sequenceDiagram
  participant BackendCase
  participant SparseKVCacheManager
  participant VanillaAttention
  participant TRTLLM
  BackendCase->>SparseKVCacheManager: create sparse paged cache
  BackendCase->>VanillaAttention: run sparse context and generation
  VanillaAttention->>SparseKVCacheManager: read and append latent cache
  BackendCase->>TRTLLM: run matching sparse phases
  BackendCase->>BackendCase: compare outputs and singleton oracle values
Loading

Possibly related PRs

Suggested reviewers: yunruis, cascade812, perkzzheng

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% 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 clearly explains the DSA integration, unified test harness, scope, test coverage, and checklist items.
Title check ✅ Passed The title follows the required format and clearly summarizes the DSA VanillaAttention reference and unified sparse backend test changes.
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.

Comment thread tests/unittest/_torch/attention/backend_capability.py Outdated
Comment thread tests/unittest/_torch/attention/model_attn_config.py Outdated
Comment thread tests/unittest/_torch/attention/test_attention_backends.py Outdated
Comment thread tests/unittest/_torch/attention/test_attention_backends.py Outdated
Comment thread tests/unittest/_torch/attention/test_attention_backends.py Outdated
Comment thread tests/unittest/_torch/attention/test_attention_backends.py Outdated
Comment thread tests/unittest/_torch/attention/test_attention_backends.py Outdated
Comment thread tests/unittest/_torch/attention/test_attention_backends.py Outdated
raise ValueError(
"Vanilla sparse MLA expects absorbed queries and latent cache, "
"not explicit K/V tensors")
return self._mla_forward_sparse(

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.

The main diff between _mla_forward_sparse and _mla_forward_generation is that _mla_forward_sparse use paged cache but _mla_forward_generation uses linear cache. Can we make vanilla always use linear cache, so that we can rename _mla_forward_generation to _mla_forward_absorption and add topk_indices handle to it to support sparse attention?

…_config

The sparse KV-cache manager takes sparse_attention_config directly, so
model_config/pretrained_config are not needed, and Vanilla can use the same
sparse cache manager as the other backends (no VANILLA special-case).

Signed-off-by: Yihan Wang <yihwang@nvidia.com>
mla_bmm2_scale = None
quant_q_buffer = None

gen_layers[layer_idx].mla_rope_generation(

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.

Both of the rope and page cache design come from the fact that tests/unittest/_torch/attention/sparse/dsa/test_dsa_sparse_mla.py uses this design. We can also update the tests in this file to remove rope for both vanilla and trtllm backend, and use linear cache for vanilla, so it aligns with the original design of vanilla.

…tion

- Remove VanillaAttention's internal sparse-MLA RoPE. The harness now applies
  RoPE on the host and feeds pre-formed inputs, using skip_mla_rope_generation
  for the absorbed generation path (matches production: the MLA module runs
  RoPE, the attention backend does not).
- Context phase feeds raw inputs so the TRTLLM MLA context kernel ropes once
  (avoids double RoPE); Vanilla and the generation path use the pre-RoPE'd
  inputs.
- Gate TRTLLM DSA to sm>=100: the trtllm-gen DynamicTokenSparse FMHA kernels
  are Blackwell-only; on Hopper MLA generation falls back to dense FlashMLA,
  which has no per-token sparse path.
- Drop the block-unit (sparse_block_size) abstraction; the suite is
  token-selection only (DSA / DeepSeek-V4). RocketKV block sparse is out of
  scope for this suite.

Signed-off-by: Yihan Wang <yihwang@nvidia.com>
@yihwang-nv

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #60331 [ run ] triggered by Bot. Commit: 1592fb9 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #60331 [ run ] completed with state FAILURE. Commit: 1592fb9
/LLM/main/L0_MergeRequest_PR pipeline #48676 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

num_kv_heads: Optional[int] = None,
quant_config: Optional[QuantConfig] = None,
q_scaling: Optional[float] = None,
pos_embd_params: Optional[PositionalEmbeddingParams] = None,

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.

pos_embd_params is unused now

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.

Removed — dropped pos_embd_params from VanillaAttention.__init__ and its import; it only fed the sparse-MLA RoPE that was removed. create_attention passes it as a kwarg, which the base backend swallows, so it's a no-op.

HAS_FLASH_MLA = False


class VanillaIndexer:

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.

If we don't use VanillaIndexer in our test suite, should we fully revert changes in this file?

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.

Done — fully reverted this file to main. VanillaIndexer is not used by the model-driven suite and has a different API than the production DSA Indexer, so the original free-function version is restored.

…indexer test

- Remove the now-unused pos_embd_params from VanillaAttention.__init__ (and its
  import); it only fed the sparse-MLA RoPE that was removed. create_attention
  passes it as a kwarg, which the base backend swallows, so this is a no-op.
- Fully revert tests/unittest/_torch/attention/sparse/test_sparse_mla_forward.py:
  VanillaIndexer is not used by the model-driven suite and has a different API
  than the production DSA Indexer, so restore the original file.

Signed-off-by: Yihan Wang <yihwang@nvidia.com>

per_token_outputs = []
for token_idx in range(q_len):
row = topk_indices[token_offset + token_idx]

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.

Can we use topk_indices to select kv and concat them in advance, so that we can directly use torch.nn.functional.scaled_dot_product_attention like dense mla case? If so, we can easily merge _mla_forward_sparse to _mla_forward_generation.

Signed-off-by: Yihan Wang <yihwang@nvidia.com>
Signed-off-by: Yihan Wang <yihwang@nvidia.com>
@yihwang-nv

Copy link
Copy Markdown
Collaborator Author

/bot run

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63935 [ run ] triggered by Bot. Commit: 3e35f63 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63935 [ run ] completed with state FAILURE. Commit: 3e35f63
/LLM/main/L0_MergeRequest_PR pipeline #51871 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

Signed-off-by: Yihan Wang <yihwang@nvidia.com>
The origin merge refactored AttentionForwardArgs and replaced the DSA
backend, breaking the vanilla-vs-TRTLLM sparse MLA comparison:

- Route caller-provided top-k through sparse_backend_args.topk_indices
  (VanillaAttention.sparse_attn_predict) and rename the dropped
  forward_args.sparse_prediction to sparse_runtime_params in vanilla.py
  and backend_case.py.
- Restore the is_vanilla branching in the test (direct selection for
  vanilla, indexer mock + sparse_backend_args for TRTLLM) and drop the
  duplicated generation forward kwargs left by the merge.
- VanillaAttention applies no RoPE itself while the kernel does via
  rope_append, so pre-apply the matching yarn RoPE to the vanilla
  q_pe/k_pe at absolute positions before the golden forward.

All 12 parametrized cases pass.

Signed-off-by: Yihan Wang <yihwang@nvidia.com>
@coderabbitai

coderabbitai Bot commented Aug 10, 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.

@yihwang-nv yihwang-nv changed the title [None][feat] Add DSA sparse attention + indexer reference to VanillaAttention; unify sparse backend tests [None][feat] Add DSA sparse attention reference to VanillaAttention and unify sparse backend tests Aug 10, 2026
VanillaAttention.sparse_kv_predict only ever returned (None, None) and
its sole caller wrote those Nones back as the already-default
sparse_runtime_params values. Vanilla handles sparse selection inline via
sparse_attn_predict (not through the sparse hooks), so the method is dead.
Drop it and the corresponding kv-index assignments.

Signed-off-by: Yihan Wang <yihwang@nvidia.com>

@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: 5

🧹 Nitpick comments (8)
tests/unittest/_torch/attention/backend_case.py (2)

316-320: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Annotate the new sparse_config parameter.

Every other parameter of _build_mla_kv_cache_manager is annotated. Add sparse_config: Optional[SparseAttentionConfig] = None, as required by the Python guideline to annotate every function.

As per coding guidelines: "Annotate every function, use None for procedures, avoid unnecessary Any and type: ignore".

🤖 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 `@tests/unittest/_torch/attention/backend_case.py` around lines 316 - 320,
Annotate the sparse_config parameter in _build_mla_kv_cache_manager as
Optional[SparseAttentionConfig] with a default of None, adding or reusing the
necessary imports while preserving the existing function behavior.

Source: Coding guidelines


1218-1222: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

The non-MLA sparse guard is duplicated.

run_backend and run_case each raise ValueError(f"Unsupported sparse contract: is_mla={case.is_mla}"). _validate_sparse_case already exists as the single validation point for sparse cases. Move the is_mla check there and let both callers rely on it.

Also applies to: 1412-1417

🤖 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 `@tests/unittest/_torch/attention/backend_case.py` around lines 1218 - 1222,
Move the non-MLA sparse validation into _validate_sparse_case, making it raise
the existing “Unsupported sparse contract” ValueError for sparse cases where
is_mla is false. Remove the duplicated guard and raise from both run_backend and
run_case, while preserving their MLA sparse execution flow and relying on
_validate_sparse_case as the single validation point.
tensorrt_llm/_torch/attention_backend/vanilla.py (3)

679-709: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Two MLA latent gather helpers now coexist.

_gather_paged_mla_latent (lines 189-208) and _load_mla_latent_cache both materialize a request's latent cache from paged blocks. The differences are HND support, BAD_PAGE_INDEX handling, and the read-offset assumption. Consider folding the HND branch into _gather_paged_mla_latent and deleting one helper, so the dense and sparse MLA paths cannot drift.

🤖 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/vanilla.py` around lines 679 - 709,
Consolidate the duplicate MLA page-materialization logic by extending
_gather_paged_mla_latent with the HND layout handling, BAD_PAGE_INDEX filtering,
and required read-offset behavior currently implemented by
_load_mla_latent_cache. Update all callers to use the unified helper, then
remove _load_mla_latent_cache so dense and sparse MLA paths share one
implementation.

818-845: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

The per-token Python loop dominates the golden runtime.

Each query token runs one index_select and two matmuls in Python. For the context phase this is one iteration per packed token, per layer. When every row of a request has the same valid count, you can gather once with latent.index_select(0, rows.flatten()), reshape to [q_len, k, d_latent], and run a single batched bmm + softmax. Keep the current loop only for ragged rows. This is optional; the current form is correct.

🤖 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/vanilla.py` around lines 818 - 845,
Optimize the per-token processing in the attention path around
_load_mla_latent_cache by detecting when each topk_indices row has the same
valid count. For uniform rows, flatten the selected indices, perform one
latent.index_select, reshape to [q_len, k, d_latent], and replace the per-token
matmuls with batched bmm and softmax; retain the existing loop for ragged rows.

926-927: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Replace the constant-name getattr with attribute access.

getattr(self.sparse_params, "indices_block_size") behaves exactly like self.sparse_params.indices_block_size, including the AttributeError on a missing field. Use direct attribute access.

♻️ Proposed change
-                    sparse_attn_indices_block_size=getattr(
-                        self.sparse_params, "indices_block_size"),
+                    sparse_attn_indices_block_size=self.sparse_params.
+                    indices_block_size,
🤖 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/vanilla.py` around lines 926 - 927, In
the attention configuration call, replace the getattr expression for
self.sparse_params.indices_block_size with direct attribute access. Keep the
existing sparse_attn_indices_block_size argument and behavior unchanged.

Source: Linters/SAST tools

tests/unittest/_torch/attention/sparse/dsa/test_dsa_sparse_mla.py (2)

194-198: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Selection determinism depends on identical RNG call ordering between the two runs.

_test_sparse_attention_mla runs once per backend and reseeds topk_generator from the same topk_seed. The two runs produce matching topk_indices only while both take exactly the same number of randperm draws in the same order. The Vanilla and TRTLLM branches diverge inside the forward loop, so a future extra draw on one branch would silently desynchronize the selections and turn the comparison into a false pass.

Consider generating the selections once outside the backend run and passing them in, or asserting that both runs produced identical topk_indices.

Also applies to: 215-219

🤖 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 `@tests/unittest/_torch/attention/sparse/dsa/test_dsa_sparse_mla.py` around
lines 194 - 198, Make top-k index generation in the shared test setup
independent of backend-specific forward-loop execution: generate the complete
topk_indices once and reuse it for both Vanilla and TRTLLM runs, or explicitly
compare the selections after each run and fail if they differ. Update the
_test_sparse_attention_mla flow and its selection-generation helper so backend
branches cannot silently consume different randperm sequences.

424-427: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Lower sparse_config before backend dispatch. get_attention_backend accepts SparseParams, while DeepSeekSparseAttentionConfig is a user-facing config. Use sparse_config.to_sparse_params() for the lookup. The "dsa" registry entry already resolves "VANILLA" to VanillaAttention; keep is_vanilla for the later backend-specific setup.

🤖 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 `@tests/unittest/_torch/attention/sparse/dsa/test_dsa_sparse_mla.py` around
lines 424 - 427, Update the backend lookup in the AttentionCls initialization to
pass sparse_config.to_sparse_params() to get_attention_backend, while preserving
the existing is_vanilla calculation for later backend-specific setup and
retaining the direct VanillaAttention selection behavior.
tests/unittest/_torch/attention/model_attn_config.py (1)

93-99: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Centralize sparse_topk on the sparse config base. SparseAttentionConfig includes variants without index_topk, so both accessors can raise AttributeError. Define a safe base-class contract, override it for DeepSeek configs, and delegate from both callers instead of reading cfg.index_topk directly.

🤖 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 `@tests/unittest/_torch/attention/model_attn_config.py` around lines 93 - 99,
Centralize the safe sparse_topk contract on the SparseAttentionConfig base
class, returning None for configurations without index_topk, and override it in
the DeepSeek config to expose the appropriate value. Update both
model_attn_config.py lines 93-99 and backend_case.py lines 151-157 so their
callers delegate to the config’s sparse_topk accessor instead of reading
cfg.index_topk directly; both sites require this delegation change.
🤖 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/vanilla.py`:
- Around line 132-143: Update the AttentionForwardArgs construction in
backend_case.py to pass the selection through
SparseBackendForwardArgs(topk_indices=...) via sparse_backend_args, rather than
supplying topk_indices as a direct AttentionForwardArgs field. Preserve
sparse_attn_predict()’s existing read from forward_args.sparse_backend_args.

In `@tests/unittest/_torch/attention/backend_case.py`:
- Around line 1456-1458: Add a TODO marker to the existing sparse-case exclusion
comment near the case.is_gen_only condition, explicitly tracking the follow-up
work to add CUDA-graph coverage for sparse cases while preserving the current
skip behavior.
- Around line 776-789: Update the _assert_cache_contains_new_tokens call in the
MLA cache validation path to use exact tolerances (atol=0.0 and rtol=0.0),
matching _run_mla_gen_backend. Keep the cache assertion exact while retaining
_tolerances(case, case.compute_dtype) only for the output comparison.
- Around line 100-104: Update BackendCase serialization to explicitly model_dump
sparse_attention_config instead of relying on asdict, and use
TypeAdapter(SparseAttentionConfig).validate_python(...) in from_dict to
reconstruct the discriminated union before sparse_topk is accessed. Add a
round-trip test covering serialization and deserialization of a BackendCase with
SparseAttentionConfig.

In `@tests/unittest/_torch/attention/sparse/dsa/test_dsa_sparse_mla.py`:
- Around line 877-887: Update the per-layer and final backend print messages in
the sparse MLA test to state that outputs were recorded rather than that the
test passed. Adjust the messages near the output assignment and final backend
log, while preserving the existing step, layer, and backend context.

---

Nitpick comments:
In `@tensorrt_llm/_torch/attention_backend/vanilla.py`:
- Around line 679-709: Consolidate the duplicate MLA page-materialization logic
by extending _gather_paged_mla_latent with the HND layout handling,
BAD_PAGE_INDEX filtering, and required read-offset behavior currently
implemented by _load_mla_latent_cache. Update all callers to use the unified
helper, then remove _load_mla_latent_cache so dense and sparse MLA paths share
one implementation.
- Around line 818-845: Optimize the per-token processing in the attention path
around _load_mla_latent_cache by detecting when each topk_indices row has the
same valid count. For uniform rows, flatten the selected indices, perform one
latent.index_select, reshape to [q_len, k, d_latent], and replace the per-token
matmuls with batched bmm and softmax; retain the existing loop for ragged rows.
- Around line 926-927: In the attention configuration call, replace the getattr
expression for self.sparse_params.indices_block_size with direct attribute
access. Keep the existing sparse_attn_indices_block_size argument and behavior
unchanged.

In `@tests/unittest/_torch/attention/backend_case.py`:
- Around line 316-320: Annotate the sparse_config parameter in
_build_mla_kv_cache_manager as Optional[SparseAttentionConfig] with a default of
None, adding or reusing the necessary imports while preserving the existing
function behavior.
- Around line 1218-1222: Move the non-MLA sparse validation into
_validate_sparse_case, making it raise the existing “Unsupported sparse
contract” ValueError for sparse cases where is_mla is false. Remove the
duplicated guard and raise from both run_backend and run_case, while preserving
their MLA sparse execution flow and relying on _validate_sparse_case as the
single validation point.

In `@tests/unittest/_torch/attention/model_attn_config.py`:
- Around line 93-99: Centralize the safe sparse_topk contract on the
SparseAttentionConfig base class, returning None for configurations without
index_topk, and override it in the DeepSeek config to expose the appropriate
value. Update both model_attn_config.py lines 93-99 and backend_case.py lines
151-157 so their callers delegate to the config’s sparse_topk accessor instead
of reading cfg.index_topk directly; both sites require this delegation change.

In `@tests/unittest/_torch/attention/sparse/dsa/test_dsa_sparse_mla.py`:
- Around line 194-198: Make top-k index generation in the shared test setup
independent of backend-specific forward-loop execution: generate the complete
topk_indices once and reuse it for both Vanilla and TRTLLM runs, or explicitly
compare the selections after each run and fail if they differ. Update the
_test_sparse_attention_mla flow and its selection-generation helper so backend
branches cannot silently consume different randperm sequences.
- Around line 424-427: Update the backend lookup in the AttentionCls
initialization to pass sparse_config.to_sparse_params() to
get_attention_backend, while preserving the existing is_vanilla calculation for
later backend-specific setup and retaining the direct VanillaAttention selection
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: b96c7533-b57f-4100-bd09-17ecbab8925c

📥 Commits

Reviewing files that changed from the base of the PR and between d0b5862 and cc2acdc.

📒 Files selected for processing (8)
  • tensorrt_llm/_torch/attention_backend/sparse/registry.py
  • tensorrt_llm/_torch/attention_backend/vanilla.py
  • tensorrt_llm/_torch/pyexecutor/py_executor_creator.py
  • tests/unittest/_torch/attention/backend_capability.py
  • tests/unittest/_torch/attention/backend_case.py
  • tests/unittest/_torch/attention/model_attn_config.py
  • tests/unittest/_torch/attention/sparse/dsa/test_dsa_sparse_mla.py
  • tests/unittest/_torch/attention/test_attention_backends.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/unittest/_torch/attention/backend_capability.py

Comment thread tensorrt_llm/_torch/attention_backend/vanilla.py
Comment on lines +100 to +104
# User-facing sparse config, lowered into backend params, metadata params, and
# the sparse KV-cache manager exactly as in production. The selection unit and
# top-k are derived from it (properties below); the attention family is
# ``is_mla``.
sparse_attention_config: Optional[SparseAttentionConfig] = None

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.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find round-trip users of BackendCase.to_dict / from_dict.
set -euo pipefail

rg -n -C 5 '\b(to_dict|from_dict)\s*\(' tests/unittest/_torch/attention/
rg -n -C 3 'class SparseAttentionConfig|SparseAttentionConfig =' tensorrt_llm/llmapi/llm_args.py

Repository: NVIDIA/TensorRT-LLM

Length of output: 1462


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- BackendCase serialization and sparse properties ---'
sed -n '1,240p' tests/unittest/_torch/attention/backend_case.py
rg -n -C 8 'class SparseAttentionConfig|SparseAttentionConfig' --glob '*.py' .

printf '%s\n' '--- All BackendCase serialization call sites ---'
rg -n -C 5 'BackendCase\.(to_dict|from_dict)|\.(to_dict|from_dict)\s*\(' --glob '*.py' tests tensorrt_llm | head -n 400

printf '%s\n' '--- Sparse-case construction and minimizer/persistence paths ---'
rg -n -C 6 'sparse_attention_config|sparse_topk|BackendCase' tests/unittest/_torch/attention --glob '*.py' | head -n 600

Repository: NVIDIA/TensorRT-LLM

Length of output: 50376


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- BackendCase implementation ---'
sed -n '60,225p' tests/unittest/_torch/attention/backend_case.py

printf '%s\n' '--- SparseAttentionConfig declarations ---'
rg -n -C 6 '^class .*SparseAttentionConfig|^SparseAttentionConfig' tensorrt_llm/llmapi/llm_args.py

printf '%s\n' '--- Explicit BackendCase serialization references ---'
rg -n -C 4 'BackendCase\.(to_dict|from_dict)|BackendCase\.__|from_dict\(.*BackendCase|to_dict\(.*BackendCase' --glob '*.py' tests tensorrt_llm

printf '%s\n' '--- Serialization-related references in attention tests ---'
rg -n -C 4 '\b(to_dict|from_dict)\b|json\.(dump|dumps|load|loads)|pickle|yaml' tests/unittest/_torch/attention --glob '*.py'

Repository: NVIDIA/TensorRT-LLM

Length of output: 14440


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
import json
from dataclasses import asdict, dataclass
from typing import Optional

try:
    from pydantic import BaseModel, TypeAdapter
except ImportError as exc:
    print(f"pydantic unavailable: {exc}")
    raise SystemExit(0)

class SparseConfig(BaseModel):
    algorithm: str
    index_topk: int

`@dataclass`
class Case:
    sparse_attention_config: Optional[SparseConfig] = None

case = Case(sparse_attention_config=SparseConfig(algorithm="dsa", index_topk=8))
payload = asdict(case)
print("asdict field type:", type(payload["sparse_attention_config"]).__name__)

try:
    json.dumps(payload)
except TypeError as exc:
    print("json.dumps(asdict(case)):", type(exc).__name__, str(exc))
else:
    print("json.dumps(asdict(case)): succeeded")

json_payload = {"sparse_attention_config": case.sparse_attention_config.model_dump()}
restored = Case(**json_payload)
print("dict-loaded field type:", type(restored.sparse_attention_config).__name__)
try:
    print("dict-loaded index_topk:", restored.sparse_attention_config.index_topk)
except AttributeError as exc:
    print("dict-loaded sparse_topk access:", type(exc).__name__, str(exc))

validated = TypeAdapter(SparseConfig).validate_python(
    json_payload["sparse_attention_config"])
print("TypeAdapter validation type:", type(validated).__name__)
PY

printf '%s\n' '--- Complete sparse config type alias ---'
sed -n '3540,3585p' tensorrt_llm/llmapi/llm_args.py

Repository: NVIDIA/TensorRT-LLM

Length of output: 1835


Preserve SparseAttentionConfig in BackendCase serialization.

SparseAttentionConfig is a discriminated Pydantic union, not a dataclass. Therefore, asdict(self) leaves it as a model, and json.dumps(case.to_dict()) fails. A dictionary loaded by from_dict() also makes sparse_topk fail. Use model_dump() and TypeAdapter(SparseAttentionConfig).validate_python(...); the type alias has no model_validate() method. Add a round-trip test.

🤖 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 `@tests/unittest/_torch/attention/backend_case.py` around lines 100 - 104,
Update BackendCase serialization to explicitly model_dump
sparse_attention_config instead of relying on asdict, and use
TypeAdapter(SparseAttentionConfig).validate_python(...) in from_dict to
reconstruct the discriminated union before sparse_topk is accessed. Add a
round-trip test covering serialization and deserialization of a BackendCase with
SparseAttentionConfig.

Comment on lines +776 to +789
expected_latents = _split_packed_tokens(inputs["expected_new_latent"], case.seq_lens)
cache_atol, cache_rtol = _tolerances(case, case.compute_dtype)
_assert_cache_contains_new_tokens(
mgr,
0,
request_ids,
case.seq_lens,
case.num_cached_tokens,
expected_latents,
kv_layout=metadata.kv_layout,
cache_kind="mla",
atol=cache_atol,
rtol=cache_rtol,
)

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

The cache-content assertion uses the loose sparse tolerance.

_tolerances(case, ...) returns SPARSE_ATOL=1e-1 / SPARSE_RTOL=1e-2 for every sparse case, because of the new early return at line 1095. This assertion compares cache bytes that the backend copied verbatim from expected_new_latent; it should be exact. _run_mla_gen_backend performs the same check with the default (0.0, 0.0).

An atol of 1e-1 on a bf16 latent lets a wrong-block or wrong-offset append pass whenever the values happen to be close. Use exact tolerances here and keep the loose tolerance only for the output comparison.

🐛 Proposed fix
         expected_latents = _split_packed_tokens(inputs["expected_new_latent"], case.seq_lens)
-        cache_atol, cache_rtol = _tolerances(case, case.compute_dtype)
         _assert_cache_contains_new_tokens(
             mgr,
             0,
             request_ids,
             case.seq_lens,
             case.num_cached_tokens,
             expected_latents,
             kv_layout=metadata.kv_layout,
             cache_kind="mla",
-            atol=cache_atol,
-            rtol=cache_rtol,
         )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
expected_latents = _split_packed_tokens(inputs["expected_new_latent"], case.seq_lens)
cache_atol, cache_rtol = _tolerances(case, case.compute_dtype)
_assert_cache_contains_new_tokens(
mgr,
0,
request_ids,
case.seq_lens,
case.num_cached_tokens,
expected_latents,
kv_layout=metadata.kv_layout,
cache_kind="mla",
atol=cache_atol,
rtol=cache_rtol,
)
expected_latents = _split_packed_tokens(inputs["expected_new_latent"], case.seq_lens)
_assert_cache_contains_new_tokens(
mgr,
0,
request_ids,
case.seq_lens,
case.num_cached_tokens,
expected_latents,
kv_layout=metadata.kv_layout,
cache_kind="mla",
)
🤖 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 `@tests/unittest/_torch/attention/backend_case.py` around lines 776 - 789,
Update the _assert_cache_contains_new_tokens call in the MLA cache validation
path to use exact tolerances (atol=0.0 and rtol=0.0), matching
_run_mla_gen_backend. Keep the cache assertion exact while retaining
_tolerances(case, case.compute_dtype) only for the output comparison.

Comment on lines +1456 to +1458
# eager golden. The sparse runner rebuilds each request's logical cache on
# the host, which is not graph-capturable, so sparse cases are skipped.
if case.is_gen_only and not case.is_sparse:

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 requested TODO for sparse CUDA-graph coverage.

A previous review asked for a TODO here so the follow-up PR that adds CUDA-graph coverage for sparse cases can be tracked. The current comment explains the exclusion but carries no marker.

Do you want me to open an issue to track sparse CUDA-graph coverage?

📝 Proposed change
         # A gen-only batch also exercises the captured-CUDA-graph path
         # (production replays a captured decode graph); it must still match the
         # eager golden. The sparse runner rebuilds each request's logical cache on
         # the host, which is not graph-capturable, so sparse cases are skipped.
+        # TODO: add CUDA-graph coverage for sparse cases in a follow-up PR.
         if case.is_gen_only and not case.is_sparse:
🤖 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 `@tests/unittest/_torch/attention/backend_case.py` around lines 1456 - 1458,
Add a TODO marker to the existing sparse-case exclusion comment near the
case.is_gen_only condition, explicitly tracking the follow-up work to add
CUDA-graph coverage for sparse cases while preserving the current skip behavior.

Comment on lines 877 to 887
print(
f"{backend_name} output mean: {result.abs().mean().item()}, max: {result.abs().max().item()}"
)
print(
f"Reference output mean: {ref_result.abs().mean().item()}, max: {ref_result.abs().max().item()}"
)
print(
f"Difference mean: {(result - ref_result).abs().mean().item()}, \
max: {(result - ref_result).abs().max().item()}"
)

# Assert results are close
atol, rtol = accuracy_dict[kv_cache_dtype]
assert torch.allclose(result, ref_result, atol=atol, rtol=rtol), (
f"Results for sparse MLA in {backend_name} backend don't match reference implementation \
at layer {layer_idx} in step {step}"
)

print(
f"Test for sparse MLA in {backend_name} backend passed at layer {layer_idx} in step {step}"
)
print(f"---- step {step} layer {layer_idx} end ----")
phase = "context" if step == 0 else f"generation_{step - 1}"
outputs[f"{phase}_layer_{layer_idx}"] = result.detach().clone()

print(f"Test for sparse MLA in {backend_name} backend passed")

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

The "passed" messages no longer describe what happened.

The per-layer and per-backend "passed" prints were accurate when this function asserted internally. The function now only records outputs; _assert_matches_vanilla performs the comparison afterwards. A reader of the log sees "passed" for a run that has not been checked, and still sees it on a run that later fails.

Reword these to state that the output was recorded.

📝 Proposed change
-                print(
-                    f"Test for sparse MLA in {backend_name} backend passed at layer {layer_idx} in step {step}"
-                )
+                print(
+                    f"Recorded sparse MLA output for {backend_name} at layer {layer_idx} in step {step}"
+                )
                 print(f"---- step {step} layer {layer_idx} end ----")
                 phase = "context" if step == 0 else f"generation_{step - 1}"
                 outputs[f"{phase}_layer_{layer_idx}"] = result.detach().clone()

-        print(f"Test for sparse MLA in {backend_name} backend passed")
+        print(f"Collected all sparse MLA outputs for the {backend_name} backend")
         return outputs
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
print(
f"{backend_name} output mean: {result.abs().mean().item()}, max: {result.abs().max().item()}"
)
print(
f"Reference output mean: {ref_result.abs().mean().item()}, max: {ref_result.abs().max().item()}"
)
print(
f"Difference mean: {(result - ref_result).abs().mean().item()}, \
max: {(result - ref_result).abs().max().item()}"
)
# Assert results are close
atol, rtol = accuracy_dict[kv_cache_dtype]
assert torch.allclose(result, ref_result, atol=atol, rtol=rtol), (
f"Results for sparse MLA in {backend_name} backend don't match reference implementation \
at layer {layer_idx} in step {step}"
)
print(
f"Test for sparse MLA in {backend_name} backend passed at layer {layer_idx} in step {step}"
)
print(f"---- step {step} layer {layer_idx} end ----")
phase = "context" if step == 0 else f"generation_{step - 1}"
outputs[f"{phase}_layer_{layer_idx}"] = result.detach().clone()
print(f"Test for sparse MLA in {backend_name} backend passed")
print(
f"{backend_name} output mean: {result.abs().mean().item()}, max: {result.abs().max().item()}"
)
print(
f"Recorded sparse MLA output for {backend_name} at layer {layer_idx} in step {step}"
)
print(f"---- step {step} layer {layer_idx} end ----")
phase = "context" if step == 0 else f"generation_{step - 1}"
outputs[f"{phase}_layer_{layer_idx}"] = result.detach().clone()
print(f"Collected all sparse MLA outputs for the {backend_name} backend")
return outputs
🤖 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 `@tests/unittest/_torch/attention/sparse/dsa/test_dsa_sparse_mla.py` around
lines 877 - 887, Update the per-layer and final backend print messages in the
sparse MLA test to state that outputs were recorded rather than that the test
passed. Adjust the messages near the output assignment and final backend log,
while preserving the existing step, layer, and backend context.

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
tests/unittest/_torch/attention/sparse/dsa/test_dsa_sparse_mla.py (2)

377-399: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add complete annotations to the changed helper functions.

  • tests/unittest/_torch/attention/sparse/dsa/test_dsa_sparse_mla.py#L377-L399: Add precise parameter annotations to _run_test_for_backend.
  • tests/unittest/_torch/attention/sparse/dsa/test_dsa_sparse_mla.py#L569-L585: Add a precise return annotation to create_layer.

As per coding guidelines, “Annotate every function” and avoid unnecessary Any.

🤖 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 `@tests/unittest/_torch/attention/sparse/dsa/test_dsa_sparse_mla.py` around
lines 377 - 399, Add precise type annotations for every parameter of
_run_test_for_backend in
tests/unittest/_torch/attention/sparse/dsa/test_dsa_sparse_mla.py lines 377-399,
avoiding unnecessary Any, and add the precise return annotation to create_layer
at lines 569-585. No direct changes are needed elsewhere.

Source: Coding guidelines


407-409: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use snake_case for the local backend class variable.

AttentionCls is a local variable. Rename it to attention_cls and update its uses at Lines 575, 642, and 669.

As per coding guidelines, “Use snake_case for files, functions, methods, locals, and mutable globals.”

🤖 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 `@tests/unittest/_torch/attention/sparse/dsa/test_dsa_sparse_mla.py` around
lines 407 - 409, Rename the local variable AttentionCls to attention_cls in the
backend selection code, and update all references at the indicated uses so the
same class remains instantiated or accessed consistently.

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.

Outside diff comments:
In `@tests/unittest/_torch/attention/sparse/dsa/test_dsa_sparse_mla.py`:
- Around line 377-399: Add precise type annotations for every parameter of
_run_test_for_backend in
tests/unittest/_torch/attention/sparse/dsa/test_dsa_sparse_mla.py lines 377-399,
avoiding unnecessary Any, and add the precise return annotation to create_layer
at lines 569-585. No direct changes are needed elsewhere.
- Around line 407-409: Rename the local variable AttentionCls to attention_cls
in the backend selection code, and update all references at the indicated uses
so the same class remains instantiated or accessed consistently.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 0a84bd2b-e66b-4fcd-9630-e33b64f5b2f8

📥 Commits

Reviewing files that changed from the base of the PR and between 434b838 and ca9744a.

📒 Files selected for processing (1)
  • tests/unittest/_torch/attention/sparse/dsa/test_dsa_sparse_mla.py

Merge the q_pe/k_pe rotate helpers into one _rope_qk_for_vanilla over a
shared _apply_yarn_rope core, unify the context vanilla/non-vanilla
forward() into a single call, and trim redundant comments.

Signed-off-by: Yihan Wang <yihwang@nvidia.com>
@yihwang-nv
yihwang-nv force-pushed the vanilla-dsa-attention branch from ca9744a to 4f7ba69 Compare August 10, 2026 11:58

@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.

🧹 Nitpick comments (1)
tests/unittest/_torch/attention/sparse/dsa/test_dsa_sparse_mla.py (1)

116-117: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use built-in generic annotations.

Replace List[int] with list[int] for both parameters.

Proposed change
-    seq_lens: List[int],
-    past_lens: List[int],
+    seq_lens: list[int],
+    past_lens: list[int],

As per coding guidelines, “prefer built-in generic types.”

🤖 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 `@tests/unittest/_torch/attention/sparse/dsa/test_dsa_sparse_mla.py` around
lines 116 - 117, Update the affected function signature by replacing both
seq_lens and past_lens annotations from List[int] to the built-in list[int]
syntax, preserving their parameter types and behavior.

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.

Nitpick comments:
In `@tests/unittest/_torch/attention/sparse/dsa/test_dsa_sparse_mla.py`:
- Around line 116-117: Update the affected function signature by replacing both
seq_lens and past_lens annotations from List[int] to the built-in list[int]
syntax, preserving their parameter types and behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 6e4e414a-7e8e-4cb2-acae-111510089533

📥 Commits

Reviewing files that changed from the base of the PR and between ca9744a and 4f7ba69.

📒 Files selected for processing (1)
  • tests/unittest/_torch/attention/sparse/dsa/test_dsa_sparse_mla.py

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.

3 participants