Skip to content

DSA: Add FP8/MXFP8 and compressed Top-K indexer paths - #370

Open
jiayus-nvidia wants to merge 7 commits into
NVIDIA:developfrom
jiayus-nvidia:jiayus/import-indexer-fp8-support
Open

DSA: Add FP8/MXFP8 and compressed Top-K indexer paths#370
jiayus-nvidia wants to merge 7 commits into
NVIDIA:developfrom
jiayus-nvidia:jiayus/import-indexer-fp8-support

Conversation

@jiayus-nvidia

@jiayus-nvidia jiayus-nvidia commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR adds FP8/MXFP8 support to the DSA indexer score paths and introduces an
SM100 compressed indexer-forward + Top-K pipeline.

The SM100 indexer score implementation is shared by dense forward and dense
recompute, while the compressed path produces Top-K indices, selected logits,
optional fused softmax, and optional LSE without materializing the full dense
score tensor.

SM100 MXFP8 indexer paths support qhead_per_kv_head ∈ {32, 64}. The QH32
epilogue is compile-time specialized separately so the existing QH64 hot path
and launch topology remain unchanged.

Key changes

FP8/MXFP8 score paths

  • Add an SM90 FP8 indexer path using E4M3 Q/K with per-token/head FP32
    descales.
  • Add SM100 MXFP8 indexer and dense-attention score recompute paths using E4M3
    Q/K with packed E8M0 block scales.
  • Share unified SM100 indexer score kernels between dense forward and dense
    indexer score recompute.
  • Support BSHD and THD inputs, including compact padded MXFP8 scale layouts for
    variable-length inputs.
  • Preserve the existing BF16 paths.

Compressed indexer forward

  • Add the SM100-only indexer_forward_top_k_wrapper.
  • Return INT32 Top-K indices, FP32 selected logits, fused FP32 softmax by
    default, and optional FP32 LSE.
  • Support BF16 and MXFP8 inputs, BSHD and THD layouts, and local or global
    output indices; global KV indices are returned by default.
  • With deterministic=True, resolve exact-value ties at the K-th boundary
    toward the smallest local KV indices. This makes the selected set
    reproducible but does not sort the output slots.
  • Support caller-owned candidate, candidate-offset, index, logit, softmax, and
    LSE buffers.
  • Support optional BF16 BSHD microbatching and dedicated BSHD/THD
    candidate-buffer sizing helpers.
  • Fix large THD candidate-buffer indexing.

Runtime and backward integration

  • Keep allocations, conversions, copies, launches, and optional local-to-global
    conversion on one caller-selected CUDA stream. The launch path does not add
    cross-stream synchronization; callers own input readiness and tensor
    lifetime.
  • Validate THD device metadata structurally without copying device-resident
    prefixes to the host. Callers guarantee valid sequence, scale, causal-offset,
    and candidate-prefix values, alignment, and backing storage.
  • Allow the fused forward softmax to be passed directly as sparse backward
    index_score, avoiding indexer-score recompute and a separate softmax.
  • Support the packed BF16 THD-to-backward path through zero-copy B=1 BSHD
    views with global Top-K indices.
  • Sparse backward consumes and overwrites attn_score and index_score;
    callers must copy either tensor if it must be preserved.
  • Remove the superseded SM100 decode KV-split and partial-LSE merge path.
  • Update documentation, reference helpers, and DSA coverage.

Validation

Validated on an NVIDIA B200 with CUDA 13.2, PyTorch 2.11, and cuDNN backend
9.20:

cd test/python

PYTHONPATH=../../python pytest -q \
  fe_api/dsa/test_DSA_mxfp8_scale_utils.py \
  fe_api/dsa/test_DSA_indexer_forward.py \
  fe_api/dsa/test_DSA_dense_score_recompute.py
# 28 passed, 6 skipped

PYTHONPATH=../../python pytest -q \
  fe_api/dsa/test_DSA_mxfp8_scale_utils.py \
  fe_api/dsa/test_DSA_indexer_forward.py \
  fe_api/dsa/test_DSA_dense_score_recompute.py \
  -k mxfp8
# 22 passed, 12 deselected

The full DSA suite completed with 70 passed, 7 skipped, 4 failed. The four
failures reproduce identically on current upstream/develop in an independent
worktree:

  • two causal standalone Top-K cases with top_k=705;
  • two SM100 sparse-backward D576 cases.

Formatting and static checks:

git diff --check upstream/develop...HEAD
git diff --name-only upstream/develop...HEAD -- '*.py' \
  | xargs python3 -m black --check -l 160
git diff --name-only upstream/develop...HEAD -- '*.py' \
  | xargs python3 -m py_compile

QH64 B200 performance was remeasured with the same inputs, 10 warmups, and 100
CUDA-event iterations:

Path Before After
Dense indexer 0.123456 ms 0.123456 ms
Compressed stage 1 0.109088 ms 0.109088 ms
Combined Top-K + softmax 0.227872 ms 0.227872 ms

Limitations / notes

  • The combined compressed forward + Top-K path is SM100-only. SM100 dense and
    compressed indexer paths currently require MQA (H_kv = 1).
  • Indexer kernels require head_dim = 128. SM100 MXFP8 additionally requires
    qhead_per_kv_head ∈ {32, 64} and sf_vec_size = 32.
  • Explicit microbatching is limited to BF16 BSHD and cannot be combined with
    MXFP8, LSE, or explicit q_causal_offsets.
  • Top-K slot order is not guaranteed to be sorted. Padded slots use index -1,
    logit -inf, and softmax 0.
  • Standalone and combined indexer Top-K both require
    1 <= top_k <= 2048, although they use different implementations.
  • FP8/MXFP8 indexer backward is not included; current backward Q/K/W gradient
    kernels require BF16 operands.
  • BSHD with explicit q_causal_offsets computes candidate offsets eagerly and
    is not CUDA-graph-capturable. THD graph capture requires explicit maximum
    sequence lengths, caller-provided candidate offsets, and preallocated
    outputs. Local indices are required only for strict zero-transient-allocation
    capture; global conversion is capturable but records temporaries in the graph
    pool.

Summary by CodeRabbit

  • New Features
    • Added compressed indexer-forward with integrated Top‑K selection (including fused softmax), optional LSE output, global index support, and deterministic tie-breaking.
    • Expanded precision support for dense workflows: FP8 on newer GPUs and MXFP8 on SM100+ with packed scale handling.
    • Added new buffer-sizing helpers and enhanced APIs for both standard and variable-length (THD) inputs.
  • Documentation
    • Updated DSA docs/README with revised GPU/precision constraints and output semantics (including LSE and masking behavior).
  • Bug Fixes
    • Improved consistency of denom placeholder allocation behavior for SM100+ compressed paths.
  • Tests
    • Added/expanded regression coverage for compressed Top‑K, FP8/MXFP8, THD scaling/packing, LSE correctness, masking, and deterministic mode.

@coderabbitai

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

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 363e6c96-0b5a-4ca5-9d0c-b7ff50ccaf0c

📥 Commits

Reviewing files that changed from the base of the PR and between b03ff43 and 734dbb9.

📒 Files selected for processing (5)
  • python/cudnn/deepseek_sparse_attention/indexer_forward/_compressed_top_k_sm100.py
  • python/cudnn/deepseek_sparse_attention/indexer_forward/_interface.py
  • python/cudnn/deepseek_sparse_attention/indexer_forward/indexer_fwd_sm90.py
  • test/python/fe_api/dsa/test_DSA_indexer_forward.py
  • test/python/fe_api/dsa/test_DSA_indexer_forward_compressed.py

📝 Walkthrough

Walkthrough

Adds FP8/MXFP8 precision support across DSA indexer forward and dense score recompute, introduces a combined SM100 compressed-logits Top-K path, and updates wrappers, kernels, scale utilities, documentation, and tests.

Changes

DSA precision and compressed Top-K forward

Layer / File(s) Summary
MXFP8 scale and instruction utilities
python/cudnn/deepseek_sparse_attention/utils/..., test/python/fe_api/dsa/test_DSA_mxfp8_scale_utils.py
Adds MXFP8 scale packing, blockscaled descriptors, GEMM support, runtime helpers, and layout tests.
Unified SM100 score kernels
score_recompute/*sm100*.py, indexer_forward/indexer_fwd_sm100*.py
Adds unified BF16/MXFP8 indexer-score kernels and MXFP8 dense-attention recompute support, including compressed output routing.
Precision-aware score recompute
score_recompute/_interface_sm100.py, score_recompute/api.py
Adds MXFP8 validation, tile dispatch, compilation paths, and precision-aware public wrappers.
SM90 indexer forward
indexer_forward/indexer_fwd_sm90.py, _interface_sm90.py
Adds FP8 Q/K scaling and optional LSE generation to the SM90 forward path.
Indexer forward APIs
indexer_forward/_interface.py, indexer_forward/api.py, indexer_forward/__init__.py, deepseek_sparse_attention/__init__.py
Adds precision dispatch, backend compilation, LSE handling, dynamic exports, and the combined Top-K wrapper.
Compressed Top-K execution
indexer_forward/_compressed_top_k_sm100.py, indexer_top_k/compress_top_k_sm100.py, indexer_top_k/api.py
Adds BSHD/THD compressed candidate processing, radix Top-K selection, fused softmax, deterministic tie handling, buffer contracts, and stream-aware execution.
Tests and documentation
test/python/fe_api/dsa/*, docs/fe-oss-apis/dsa.md, python/cudnn/deepseek_sparse_attention/README.md
Adds precision and compressed-path validation and documents the revised architecture, support matrix, and API contracts.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
    participant Caller
    participant TopKWrapper
    participant IndexerInterface
    participant Stage1IndexerScore
    participant Stage2TopK

    Caller->>TopKWrapper: Call compressed indexer forward
    TopKWrapper->>IndexerInterface: Dispatch compressed logits
    IndexerInterface->>Stage1IndexerScore: Compute compact candidate logits
    Stage1IndexerScore-->>IndexerInterface: Return candidate buffer and optional LSE
    IndexerInterface->>Stage2TopK: Select Top-K and optional softmax
    Stage2TopK-->>TopKWrapper: Return indices, logits, and softmax
    TopKWrapper-->>Caller: Return TupleDict
Loading
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning It includes Summary and Testing, but misses the required Affected area, Why, Related issues, and API/compatibility sections from the template. Add the missing template sections and fill them out, especially affected area, why, related issues, and a dedicated API/compatibility impact note.
Docstring Coverage ⚠️ Warning Docstring coverage is 39.58% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main change: FP8/MXFP8 support plus compressed Top-K indexer paths.
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.

🧹 Nitpick comments (5)
python/cudnn/deepseek_sparse_attention/utils/sm100/mma_desc.py (2)

151-224: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

No dedicated unit tests for the new blockscaled descriptor-packing logic.

make_blockscaled_instr_desc/blockscaled_mma_op_to_idesc implement intricate bit-packing for the SM100 MXF8F6F4 idesc, but no test file analogous to test_DSA_mxfp8_scale_utils.py exercises this packing directly (only indirectly through downstream kernel correctness tests, if any). A focused unit test asserting expected bit values for representative (M, N, sf_id, major) combinations would catch regressions independent of full kernel execution.

As per path instructions for python/cudnn/**, which say to check "whether there are test cases in test/python/fe_api".

🤖 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 `@python/cudnn/deepseek_sparse_attention/utils/sm100/mma_desc.py` around lines
151 - 224, Add focused unit coverage for the new blockscaled descriptor packing
by creating tests under test/python/fe_api for make_blockscaled_instr_desc and
blockscaled_mma_op_to_idesc. Exercise representative M/N, sf_id, and major
combinations, and assert the returned descriptor has the expected bit fields, so
the SM100 MXF8F6F4 packing logic is validated directly instead of only through
downstream kernel tests.

82-89: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Fallback getattr(..., None) could silently misclassify if cutlass_type is unexpectedly None.

If none of the type attributes exist in the installed cutlass module and cutlass_type itself happens to be None, the first is None comparison would incorrectly match and return MXF8F6F4Format.E4M3 instead of raising the intended TypeError. This is unlikely in normal use (real dtype objects are always passed) but the redundant dual-name checks (FloatE4M3FN/Float8E4M3FN) suggest uncertainty about which name is available in the installed cutlass version.

🛡️ Safer alternative
-    if cutlass_type is getattr(cutlass, "FloatE4M3FN", None):
-        return MXF8F6F4Format.E4M3
-    if cutlass_type is getattr(cutlass, "Float8E4M3FN", None):
-        return MXF8F6F4Format.E4M3
-    if cutlass_type is getattr(cutlass, "FloatE5M2", None):
-        return MXF8F6F4Format.E5M2
-    if cutlass_type is getattr(cutlass, "Float8E5M2", None):
-        return MXF8F6F4Format.E5M2
+    e4m3_names = ("FloatE4M3FN", "Float8E4M3FN")
+    e5m2_names = ("FloatE5M2", "Float8E5M2")
+    if any(cutlass_type is getattr(cutlass, name, object()) for name in e4m3_names):
+        return MXF8F6F4Format.E4M3
+    if any(cutlass_type is getattr(cutlass, name, object()) for name in e5m2_names):
+        return MXF8F6F4Format.E5M2
🤖 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 `@python/cudnn/deepseek_sparse_attention/utils/sm100/mma_desc.py` around lines
82 - 89, The dtype-to-format mapping in the helper that checks `cutlass_type`
against `FloatE4M3FN`, `Float8E4M3FN`, `FloatE5M2`, and `Float8E5M2` can
misclassify a `None` input because `getattr(..., None)` makes the first
comparison match accidentally. Update this conversion logic to avoid treating a
missing cutlass symbol or a `None` dtype as a valid match, and keep the intended
`TypeError` path in place for unsupported inputs while still handling the
alternate cutlass type names.
python/cudnn/deepseek_sparse_attention/utils/tensor_conversion.py (1)

15-32: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Docstring doesn't cover the new parameter annotations.

to_cute_tensor now has full type hints but the docstring still only describes the return in one line; assumed_align, leading_dim, fully_dynamic, enable_tvm_ffi, and divisibility aren't documented.

As per path instructions for python/cudnn/**, which say to "Focus on documentation."

🤖 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 `@python/cudnn/deepseek_sparse_attention/utils/tensor_conversion.py` around
lines 15 - 32, The to_cute_tensor docstring is missing documentation for its
newly annotated parameters. Update the docstring in to_cute_tensor to describe
assumed_align, leading_dim, fully_dynamic, enable_tvm_ffi, and divisibility,
while keeping the return description accurate; use the existing function
signature in tensor_conversion.py as the reference point.
python/cudnn/deepseek_sparse_attention/indexer_forward/indexer_fwd_sm90.py (1)

52-98: 📐 Maintainability & Code Quality | 🔵 Trivial

Missing test coverage for the generic FP8 epilogue and varlen+FP8 on SM90.

The new test_DSA_indexer_forward_wrapper_fp8_sm90_matches_dequant_reference test only exercises qhead_per_kv_head=64 with divisible shapes, which routes through use_fast_qh64_epilogue/use_unchecked_qh64_full/use_unchecked_qh64_masked (lines 95-97). The generic _epilogue_store_to_gmem FP8 path (qhead_per_kv_head=32, or shapes that don't satisfy the "unchecked" divisibility conditions) and the varlen (THD) + FP8 combination on SM90 appear untested in test/python/fe_api/dsa/.

Given the amount of new FP8-specific branching (split-warpgroup producer/consumer, rKScale shared-memory scale application, LSE accumulation), consider adding at least one test with qhead_per_kv_head=32 and one varlen+FP8 SM90 test.

Based on path instructions: "Focus on whether there are test cases in test/python/fe_api" for python/cudnn/** files.

Also applies to: 369-535

🤖 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 `@python/cudnn/deepseek_sparse_attention/indexer_forward/indexer_fwd_sm90.py`
around lines 52 - 98, Add test coverage in test/python/fe_api for the SM90 FP8
forward path beyond the current qhead_per_kvhead=64 fast epilogue case: add one
case that forces the generic _epilogue_store_to_gmem branch by using
qhead_per_kvhead=32 or a shape that does not satisfy
use_unchecked_qh64_full/use_unchecked_qh64_masked in IndexerFwdSM90, and add one
varlen (THD) + FP8 SM90 test that exercises the is_varlen path with FP8
scales/LSE handling. Keep the existing reference-matching style used by
test_DSA_indexer_forward_wrapper_fp8_sm90_matches_dequant_reference so the new
cases verify the generic FP8 epilogue and varlen+FP8 behavior.

Source: Path instructions

python/cudnn/deepseek_sparse_attention/indexer_forward/api.py (1)

209-215: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Document the newly added public parameters. The indexer_forward_wrapper docstring still only describes {'scores'} and q_causal_offsets, but the signature now exposes precision, q_scale, k_scale, sf_vec_size, return_lse, and lse_out. It's also worth noting that return_lse/lse_out are only honored on SM90 (SM100 raises NotImplementedError) so callers aren't surprised. As per path instructions ("Focus on documentation").

🤖 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 `@python/cudnn/deepseek_sparse_attention/indexer_forward/api.py` around lines
209 - 215, Update the indexer_forward_wrapper docstring to document all newly
exposed public parameters: precision, q_scale, k_scale, sf_vec_size, return_lse,
and lse_out, along with any expected behavior for the outputs. Also note in the
wrapper docs that return_lse and lse_out are only supported on SM90, while SM100
raises NotImplementedError, so callers understand the hardware-specific
limitation.

Source: Path instructions

🤖 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 `@python/cudnn/deepseek_sparse_attention/indexer_forward/api.py`:
- Around line 209-215: Update the indexer_forward_wrapper docstring to document
all newly exposed public parameters: precision, q_scale, k_scale, sf_vec_size,
return_lse, and lse_out, along with any expected behavior for the outputs. Also
note in the wrapper docs that return_lse and lse_out are only supported on SM90,
while SM100 raises NotImplementedError, so callers understand the
hardware-specific limitation.

In `@python/cudnn/deepseek_sparse_attention/indexer_forward/indexer_fwd_sm90.py`:
- Around line 52-98: Add test coverage in test/python/fe_api for the SM90 FP8
forward path beyond the current qhead_per_kvhead=64 fast epilogue case: add one
case that forces the generic _epilogue_store_to_gmem branch by using
qhead_per_kvhead=32 or a shape that does not satisfy
use_unchecked_qh64_full/use_unchecked_qh64_masked in IndexerFwdSM90, and add one
varlen (THD) + FP8 SM90 test that exercises the is_varlen path with FP8
scales/LSE handling. Keep the existing reference-matching style used by
test_DSA_indexer_forward_wrapper_fp8_sm90_matches_dequant_reference so the new
cases verify the generic FP8 epilogue and varlen+FP8 behavior.

In `@python/cudnn/deepseek_sparse_attention/utils/sm100/mma_desc.py`:
- Around line 151-224: Add focused unit coverage for the new blockscaled
descriptor packing by creating tests under test/python/fe_api for
make_blockscaled_instr_desc and blockscaled_mma_op_to_idesc. Exercise
representative M/N, sf_id, and major combinations, and assert the returned
descriptor has the expected bit fields, so the SM100 MXF8F6F4 packing logic is
validated directly instead of only through downstream kernel tests.
- Around line 82-89: The dtype-to-format mapping in the helper that checks
`cutlass_type` against `FloatE4M3FN`, `Float8E4M3FN`, `FloatE5M2`, and
`Float8E5M2` can misclassify a `None` input because `getattr(..., None)` makes
the first comparison match accidentally. Update this conversion logic to avoid
treating a missing cutlass symbol or a `None` dtype as a valid match, and keep
the intended `TypeError` path in place for unsupported inputs while still
handling the alternate cutlass type names.

In `@python/cudnn/deepseek_sparse_attention/utils/tensor_conversion.py`:
- Around line 15-32: The to_cute_tensor docstring is missing documentation for
its newly annotated parameters. Update the docstring in to_cute_tensor to
describe assumed_align, leading_dim, fully_dynamic, enable_tvm_ffi, and
divisibility, while keeping the return description accurate; use the existing
function signature in tensor_conversion.py as the reference point.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 7d40af09-f3c0-42ba-80c9-1f1a4f4868cc

📥 Commits

Reviewing files that changed from the base of the PR and between f005383 and 8c3ea50.

📒 Files selected for processing (31)
  • docs/fe-oss-apis/dsa.md
  • python/cudnn/deepseek_sparse_attention/README.md
  • python/cudnn/deepseek_sparse_attention/__init__.py
  • python/cudnn/deepseek_sparse_attention/indexer_backward/api.py
  • python/cudnn/deepseek_sparse_attention/indexer_forward/__init__.py
  • python/cudnn/deepseek_sparse_attention/indexer_forward/_compressed_top_k_sm100.py
  • python/cudnn/deepseek_sparse_attention/indexer_forward/_interface.py
  • python/cudnn/deepseek_sparse_attention/indexer_forward/_interface_sm90.py
  • python/cudnn/deepseek_sparse_attention/indexer_forward/api.py
  • python/cudnn/deepseek_sparse_attention/indexer_forward/indexer_fwd_sm100.py
  • python/cudnn/deepseek_sparse_attention/indexer_forward/indexer_fwd_sm100_mxfp8.py
  • python/cudnn/deepseek_sparse_attention/indexer_forward/indexer_fwd_sm90.py
  • python/cudnn/deepseek_sparse_attention/indexer_top_k/api.py
  • python/cudnn/deepseek_sparse_attention/indexer_top_k/compress_top_k_sm100.py
  • python/cudnn/deepseek_sparse_attention/score_recompute/_interface_sm100.py
  • python/cudnn/deepseek_sparse_attention/score_recompute/api.py
  • python/cudnn/deepseek_sparse_attention/score_recompute/dense_score_recompute_sm100.py
  • python/cudnn/deepseek_sparse_attention/score_recompute/dense_score_recompute_sm100_mxfp8.py
  • python/cudnn/deepseek_sparse_attention/score_recompute/indexer_score_unified_sm100.py
  • python/cudnn/deepseek_sparse_attention/score_recompute/indexer_score_unified_sm100_mxfp8.py
  • python/cudnn/deepseek_sparse_attention/utils/runtime.py
  • python/cudnn/deepseek_sparse_attention/utils/sm100/gemm.py
  • python/cudnn/deepseek_sparse_attention/utils/sm100/mma_desc.py
  • python/cudnn/deepseek_sparse_attention/utils/sm100/mxfp8_scale_utils.py
  • python/cudnn/deepseek_sparse_attention/utils/tensor_conversion.py
  • test/python/fe_api/dsa/dsa_reference.py
  • test/python/fe_api/dsa/dsa_utils.py
  • test/python/fe_api/dsa/test_DSA_dense_score_recompute.py
  • test/python/fe_api/dsa/test_DSA_indexer_forward.py
  • test/python/fe_api/dsa/test_DSA_indexer_forward_compressed.py
  • test/python/fe_api/dsa/test_DSA_mxfp8_scale_utils.py

@Anerudhan

Copy link
Copy Markdown
Collaborator

@cudnn-ci-bot run

@cudnn-ci-bot

Copy link
Copy Markdown

🚀 Running mirror pipeline

Branch: cudnn-gh/pr-370-8c3ea50
Pipeline: 57505265

@jiayus-nvidia
jiayus-nvidia force-pushed the jiayus/import-indexer-fp8-support branch from 6bda0b9 to d7579a8 Compare July 13, 2026 06:34
@jiayus-nvidia
jiayus-nvidia marked this pull request as draft July 14, 2026 07:54
@jiayus-nvidia

Copy link
Copy Markdown
Contributor Author

WIP for adding deterministic and e2e test

@jiayus-nvidia
jiayus-nvidia force-pushed the jiayus/import-indexer-fp8-support branch from 0821bf2 to 061e6cd Compare July 24, 2026 02:58
Share the SM100 unified score kernels between indexer forward and dense recompute, add the SM90 FP8 path, and port the MXFP8 scale helpers and coverage. Keep compressed-logits/top-k support out of scope.
Port the SM100 compact-logits path and fold in the latest indexer optimizations: fused Top-K softmax, THD MXFP8, BF16/MXFP8 LSE for BSHD and THD, caller-owned output buffers, MQA validation, and the backward softmax fast path. Remove the superseded decode KV-split and partial-LSE merge path.
Port /code/indexer commit b731ca5 to the cudnn-frontend DSA layout.
@jiayus-nvidia
jiayus-nvidia force-pushed the jiayus/import-indexer-fp8-support branch from 7e07396 to b03ff43 Compare July 29, 2026 09:38
@jiayus-nvidia
jiayus-nvidia marked this pull request as ready for review July 29, 2026 09:49

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

🧹 Nitpick comments (10)
python/cudnn/deepseek_sparse_attention/score_recompute/indexer_score_unified_sm100_mxfp8.py (2)

996-999: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Drop the unused participants and neg_log2_e.

K_consumer / KScale_consumer are never used — the MMA warp drives those pipelines through pipeline_K.consumer_wait(K_mma_state) / pipeline_KScale.consumer_wait(KScale_mma_state) directly (Lines 1400, 1421). neg_log2_e at Line 998 is also dead; the epilogues compute their own log2_e. Ruff flags the first two as RUF059.

♻️ Proposed cleanup
-        neg_log2_e = Float32(-math.log2(math.e))
-
         Q_producer, Q_consumer = pipeline_Q.make_participants()
-        K_producer, K_consumer = pipeline_K.make_participants()
-        KScale_producer, KScale_consumer = pipeline_KScale.make_participants()
+        K_producer, _K_consumer = pipeline_K.make_participants()
+        KScale_producer, _KScale_consumer = pipeline_KScale.make_participants()

Also applies to: 1146-1148

🤖 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
`@python/cudnn/deepseek_sparse_attention/score_recompute/indexer_score_unified_sm100_mxfp8.py`
around lines 996 - 999, Remove the unused K_consumer and KScale_consumer
participants from the relevant setup, and delete the unused neg_log2_e
assignment near warp_idx and tidx in the unified score recompute flow. Preserve
the direct pipeline_K.consumer_wait and pipeline_KScale.consumer_wait calls
using their existing MMA states.

Source: Linters/SAST tools


502-527: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

max_seqlen_k is threaded through both epilogue helpers but never read.

Both signatures accept max_seqlen_k and every call site passes it (Lines 1534, 1559, 1628, 1653), yet neither body uses it — masking uses seqlen_k and col_limit. If it is kept only for signature parity with the BF16 base epilogues, a short comment saying so avoids a reader assuming padded-extent masking happens somewhere here; otherwise drop it.

Also applies to: 723-748

🤖 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
`@python/cudnn/deepseek_sparse_attention/score_recompute/indexer_score_unified_sm100_mxfp8.py`
around lines 502 - 527, Remove the unused max_seqlen_k parameter from both dense
single-query epilogue helpers and update all call sites accordingly, unless
signature parity with the BF16 base epilogues is required. If retaining it, add
a concise comment in each helper clarifying that masking uses seqlen_k and
col_limit rather than max_seqlen_k.
python/cudnn/deepseek_sparse_attention/utils/sm100/mxfp8_scale_utils.py (1)

196-229: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Padded scale rows are left as zero E8M0.

out is zero-initialized and only [q_scale0, q_scale0 + q_len*qhpkv) is written, so padded rows carry E8M0 0x00 (= 2^-127). That is only safe because the kernel masks those packed-M rows out; if any future tile path reads them, the tiny-but-nonzero factor multiplies garbage FP8 data rather than being ignored. Worth a short comment recording that invariant here so the zero-fill is not mistaken for "unused".

🤖 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 `@python/cudnn/deepseek_sparse_attention/utils/sm100/mxfp8_scale_utils.py`
around lines 196 - 229, The zero-initialized padding in the output of the
scale-packing function should be documented as intentionally retained E8M0 zero
values. Add a short comment adjacent to the `torch.zeros` initialization or the
per-batch write explaining that padded rows remain zero and are safe only
because downstream kernels mask them out; do not change the allocation or
packing behavior.
python/cudnn/deepseek_sparse_attention/score_recompute/_interface_sm100.py (2)

979-991: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Ruff RUF005: build the tuple with unpacking.

♻️ Proposed fix
-        base_compile_key = (
+        compile_key = (
+            "dense_indexer",
             q.dtype,
             head_dim,
             qhead_per_kv_head,
             m_block_size,
             n_block_size,
             k_block_size,
             kv_stage,
             ratio,
             is_varlen,
             q_causal_offsets is not None,
         )
-        compile_key = ("dense_indexer",) + base_compile_key
🤖 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 `@python/cudnn/deepseek_sparse_attention/score_recompute/_interface_sm100.py`
around lines 979 - 991, Update the compile_key construction in the surrounding
score-recompute interface to use tuple unpacking when prefixing "dense_indexer"
to base_compile_key, preserving the existing key contents and ordering.

Source: Linters/SAST tools


1485-1499: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Public docstrings weren't updated for the new precision/MXFP8 parameters. Both public entry points gained precision, q_scale, k_scale, cu_seqlens_q_scale_padded, cu_seqlens_k_scale_padded, sf_vec_size, and k_block_size, but their Args blocks still describe only the BF16 contract.

  • python/cudnn/deepseek_sparse_attention/score_recompute/_interface_sm100.py#L1485-L1499: document the new params in dense_indexer_score_recompute and note that Q/K are FP8 (float8_e4m3fn) when precision="mxfp8", with packed E8M0 scale shape expectations.
  • python/cudnn/deepseek_sparse_attention/score_recompute/_interface_sm100.py#L1567-L1581: same additions for dense_attn_score_recompute, plus the MXFP8 out prefill semantics (zeros rather than -inf).
🤖 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 `@python/cudnn/deepseek_sparse_attention/score_recompute/_interface_sm100.py`
around lines 1485 - 1499, Update the public Args docstrings for
dense_indexer_score_recompute at
python/cudnn/deepseek_sparse_attention/score_recompute/_interface_sm100.py:1485-1499
and dense_attn_score_recompute at :1567-1581 to document precision, q_scale,
k_scale, cu_seqlens_q_scale_padded, cu_seqlens_k_scale_padded, sf_vec_size, and
k_block_size, including packed E8M0 scale shape expectations. State that
precision="mxfp8" uses float8_e4m3fn Q/K, and additionally document for
dense_attn_score_recompute that MXFP8 out is prefilled with zeros rather than
-inf.
test/python/fe_api/dsa/test_DSA_indexer_forward_compressed.py (1)

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

Unused (s_q, s_k) unpacking in both per-batch loops (Ruff B007). Both loops derive their bounds from cu_q_host/cu_k_host, so the unpacked shape values are dead.

  • test/python/fe_api/dsa/test_DSA_indexer_forward_compressed.py#L725-L725: replace for batch, (s_q, s_k) in enumerate(shapes): with for batch in range(len(shapes)):.
  • test/python/fe_api/dsa/test_DSA_indexer_forward_compressed.py#L831-L831: apply the same change to this loop.
🤖 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 `@test/python/fe_api/dsa/test_DSA_indexer_forward_compressed.py` at line 725,
The two per-batch loops in
test/python/fe_api/dsa/test_DSA_indexer_forward_compressed.py at lines 725-725
and 831-831 unnecessarily unpack unused shape values. Update both loops to
iterate over batch indices using the length of shapes, while preserving their
existing bodies and bounds derived from cu_q_host and cu_k_host.

Source: Linters/SAST tools

python/cudnn/deepseek_sparse_attention/indexer_forward/__init__.py (1)

11-17: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Sort __all__ to satisfy Ruff RUF022.

♻️ Proposed fix
 __all__ = [
     "IndexerForward",
-    "indexer_forward_wrapper",
-    "indexer_forward_top_k_wrapper",
     "compress_topk_cand_buffer_size",
     "compress_topk_cand_buffer_size_thd",
+    "indexer_forward_top_k_wrapper",
+    "indexer_forward_wrapper",
 ]
🤖 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 `@python/cudnn/deepseek_sparse_attention/indexer_forward/__init__.py` around
lines 11 - 17, Sort the exported names in `__all__` alphabetically in the module
containing `IndexerForward` and the wrapper functions, preserving all existing
entries and their export behavior.

Source: Linters/SAST tools

python/cudnn/deepseek_sparse_attention/indexer_top_k/compress_top_k_sm100.py (1)

992-998: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Sort __all__ to satisfy Ruff RUF022.

♻️ Proposed fix
 __all__ = [
     "CompressTopkStage2",
+    "build_compact_buffer",
     "compress_stage2_topk",
     "compress_stage2_topk_varlen",
-    "build_compact_buffer",
     "per_batch_floats",
 ]
🤖 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 `@python/cudnn/deepseek_sparse_attention/indexer_top_k/compress_top_k_sm100.py`
around lines 992 - 998, Sort the exported names in __all__ alphabetically to
satisfy Ruff RUF022, while preserving the same symbols and export behavior.

Source: Linters/SAST tools

python/cudnn/deepseek_sparse_attention/score_recompute/dense_score_recompute_sm100_mxfp8.py (1)

543-547: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

rLSE_all materializes all 128 tile rows but only 64 are used.

The consumer loop indexes rLSE_all[q_token_stage * qhpkv + ...], i.e. a single 64-entry window, yet a 128-element register tensor is allocated and copied. With num_regs_epilogue = 96 this is a likely spill source. The *_head_half variants already offset sLSE and size the register tensor to the used range; consider the same here.

🤖 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
`@python/cudnn/deepseek_sparse_attention/score_recompute/dense_score_recompute_sm100_mxfp8.py`
around lines 543 - 547, Resize rLSE_all in the score recompute path to the
64-entry range actually consumed by the q_token_stage indexing, matching the
offset-and-sized approach used by the *_head_half variants. Update the
associated sLSE view or copy bounds as needed so only that window is
materialized, while preserving the existing consumer indexing behavior.
python/cudnn/deepseek_sparse_attention/indexer_forward/_compressed_top_k_sm100.py (1)

1425-1428: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Dead branch and stale comment for sq_b.

sq_b is unconditionally None at Line 1428, so the guard at Line 1511 is always taken and the comment ("capture path skipped the eager per-batch compute above") describes code that no longer exists. Collapse it to a direct computation.

♻️ Proposed cleanup
-    # Only needed for the optional GPU-side local-to-global conversion. Device
-    # prefix values are caller-owned and are not copied to the host for
-    # validation.
-    sq_b = None
-
-        if sq_b is None:  # capture path skipped the eager per-batch compute above
-            sq_b = (cu_q32[1:] - cu_q32[:-1]).to(torch.int64)
+        # Derived on device only for the local->global conversion; the caller's
+        # prefix values are never read back to the host.
+        sq_b = (cu_q32[1:] - cu_q32[:-1]).to(torch.int64)

Also applies to: 1508-1512

🤖 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
`@python/cudnn/deepseek_sparse_attention/indexer_forward/_compressed_top_k_sm100.py`
around lines 1425 - 1428, Remove the unconditional sq_b = None assignment and
its stale explanatory comment. In the local-to-global conversion logic around
the sq_b guard, eliminate the dead conditional and execute the existing
computation directly, preserving the behavior from the currently reachable
branch.
🤖 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
`@python/cudnn/deepseek_sparse_attention/indexer_forward/_compressed_top_k_sm100.py`:
- Around line 106-121: Update _get_fwd_unified_denom_placeholder so THD calls
with varying one-dimensional shapes reuse a bounded per-device float32 buffer
instead of caching every full shape. Grow the buffer only when the requested
size exceeds its capacity, return a slice matching shape, and preserve the
existing behavior for other shapes and devices.

In `@python/cudnn/deepseek_sparse_attention/indexer_forward/indexer_fwd_sm90.py`:
- Line 134: Resize sLseReduce_struct at line 134 to 8 * self.q_tokens_per_tile
and derive lse_reduce_base at each _write_lse_from_local_accum call from
q_stage_idx * self.q_tokens_per_stage * 8, preserving the existing stage
indexing. At line 1316, update get_tensor’s layout extent to the same
geometry-derived size instead of (32,); both sites must support
qhead_per_kvhead=16 without out-of-bounds writes.

In `@python/cudnn/deepseek_sparse_attention/score_recompute/_interface_sm100.py`:
- Around line 1249-1252: Update the MXFP8 initialization condition in the
relevant score recompute interface to include the head_dim=512 and
qhead_per_kv_head=64 dual-epilogue configuration, while preserving the existing
handling for the other MXFP8 cases. Keep denom_out.zero_() in this path, and
remove the redundant out.zero_() call.

In `@test/python/fe_api/dsa/test_DSA_indexer_forward_compressed.py`:
- Around line 42-60: Gate
test_compressed_indexer_rejects_unsupported_qhead_group_before_launch to SM100
support and skip it when the optional cudnn[cutedsl] dependency is unavailable,
using the same capability checks and import pattern as the other tests in this
file. Ensure unsupported architectures or backends are skipped before importing
or invoking DSA, while preserving the existing qhead_per_kv_head ValueError
assertion on supported environments.

---

Nitpick comments:
In `@python/cudnn/deepseek_sparse_attention/indexer_forward/__init__.py`:
- Around line 11-17: Sort the exported names in `__all__` alphabetically in the
module containing `IndexerForward` and the wrapper functions, preserving all
existing entries and their export behavior.

In
`@python/cudnn/deepseek_sparse_attention/indexer_forward/_compressed_top_k_sm100.py`:
- Around line 1425-1428: Remove the unconditional sq_b = None assignment and its
stale explanatory comment. In the local-to-global conversion logic around the
sq_b guard, eliminate the dead conditional and execute the existing computation
directly, preserving the behavior from the currently reachable branch.

In
`@python/cudnn/deepseek_sparse_attention/indexer_top_k/compress_top_k_sm100.py`:
- Around line 992-998: Sort the exported names in __all__ alphabetically to
satisfy Ruff RUF022, while preserving the same symbols and export behavior.

In `@python/cudnn/deepseek_sparse_attention/score_recompute/_interface_sm100.py`:
- Around line 979-991: Update the compile_key construction in the surrounding
score-recompute interface to use tuple unpacking when prefixing "dense_indexer"
to base_compile_key, preserving the existing key contents and ordering.
- Around line 1485-1499: Update the public Args docstrings for
dense_indexer_score_recompute at
python/cudnn/deepseek_sparse_attention/score_recompute/_interface_sm100.py:1485-1499
and dense_attn_score_recompute at :1567-1581 to document precision, q_scale,
k_scale, cu_seqlens_q_scale_padded, cu_seqlens_k_scale_padded, sf_vec_size, and
k_block_size, including packed E8M0 scale shape expectations. State that
precision="mxfp8" uses float8_e4m3fn Q/K, and additionally document for
dense_attn_score_recompute that MXFP8 out is prefilled with zeros rather than
-inf.

In
`@python/cudnn/deepseek_sparse_attention/score_recompute/dense_score_recompute_sm100_mxfp8.py`:
- Around line 543-547: Resize rLSE_all in the score recompute path to the
64-entry range actually consumed by the q_token_stage indexing, matching the
offset-and-sized approach used by the *_head_half variants. Update the
associated sLSE view or copy bounds as needed so only that window is
materialized, while preserving the existing consumer indexing behavior.

In
`@python/cudnn/deepseek_sparse_attention/score_recompute/indexer_score_unified_sm100_mxfp8.py`:
- Around line 996-999: Remove the unused K_consumer and KScale_consumer
participants from the relevant setup, and delete the unused neg_log2_e
assignment near warp_idx and tidx in the unified score recompute flow. Preserve
the direct pipeline_K.consumer_wait and pipeline_KScale.consumer_wait calls
using their existing MMA states.
- Around line 502-527: Remove the unused max_seqlen_k parameter from both dense
single-query epilogue helpers and update all call sites accordingly, unless
signature parity with the BF16 base epilogues is required. If retaining it, add
a concise comment in each helper clarifying that masking uses seqlen_k and
col_limit rather than max_seqlen_k.

In `@python/cudnn/deepseek_sparse_attention/utils/sm100/mxfp8_scale_utils.py`:
- Around line 196-229: The zero-initialized padding in the output of the
scale-packing function should be documented as intentionally retained E8M0 zero
values. Add a short comment adjacent to the `torch.zeros` initialization or the
per-batch write explaining that padded rows remain zero and are safe only
because downstream kernels mask them out; do not change the allocation or
packing behavior.

In `@test/python/fe_api/dsa/test_DSA_indexer_forward_compressed.py`:
- Line 725: The two per-batch loops in
test/python/fe_api/dsa/test_DSA_indexer_forward_compressed.py at lines 725-725
and 831-831 unnecessarily unpack unused shape values. Update both loops to
iterate over batch indices using the length of shapes, while preserving their
existing bodies and bounds derived from cu_q_host and cu_k_host.
🪄 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: 29e54836-c989-421c-8b80-a8f02748f61a

📥 Commits

Reviewing files that changed from the base of the PR and between d7579a8 and b03ff43.

📒 Files selected for processing (31)
  • docs/fe-oss-apis/dsa.md
  • python/cudnn/deepseek_sparse_attention/README.md
  • python/cudnn/deepseek_sparse_attention/__init__.py
  • python/cudnn/deepseek_sparse_attention/indexer_backward/api.py
  • python/cudnn/deepseek_sparse_attention/indexer_forward/__init__.py
  • python/cudnn/deepseek_sparse_attention/indexer_forward/_compressed_top_k_sm100.py
  • python/cudnn/deepseek_sparse_attention/indexer_forward/_interface.py
  • python/cudnn/deepseek_sparse_attention/indexer_forward/_interface_sm90.py
  • python/cudnn/deepseek_sparse_attention/indexer_forward/api.py
  • python/cudnn/deepseek_sparse_attention/indexer_forward/indexer_fwd_sm100.py
  • python/cudnn/deepseek_sparse_attention/indexer_forward/indexer_fwd_sm100_mxfp8.py
  • python/cudnn/deepseek_sparse_attention/indexer_forward/indexer_fwd_sm90.py
  • python/cudnn/deepseek_sparse_attention/indexer_top_k/api.py
  • python/cudnn/deepseek_sparse_attention/indexer_top_k/compress_top_k_sm100.py
  • python/cudnn/deepseek_sparse_attention/score_recompute/_interface_sm100.py
  • python/cudnn/deepseek_sparse_attention/score_recompute/api.py
  • python/cudnn/deepseek_sparse_attention/score_recompute/dense_score_recompute_sm100.py
  • python/cudnn/deepseek_sparse_attention/score_recompute/dense_score_recompute_sm100_mxfp8.py
  • python/cudnn/deepseek_sparse_attention/score_recompute/indexer_score_unified_sm100.py
  • python/cudnn/deepseek_sparse_attention/score_recompute/indexer_score_unified_sm100_mxfp8.py
  • python/cudnn/deepseek_sparse_attention/utils/runtime.py
  • python/cudnn/deepseek_sparse_attention/utils/sm100/gemm.py
  • python/cudnn/deepseek_sparse_attention/utils/sm100/mma_desc.py
  • python/cudnn/deepseek_sparse_attention/utils/sm100/mxfp8_scale_utils.py
  • python/cudnn/deepseek_sparse_attention/utils/tensor_conversion.py
  • test/python/fe_api/dsa/dsa_reference.py
  • test/python/fe_api/dsa/dsa_utils.py
  • test/python/fe_api/dsa/test_DSA_dense_score_recompute.py
  • test/python/fe_api/dsa/test_DSA_indexer_forward.py
  • test/python/fe_api/dsa/test_DSA_indexer_forward_compressed.py
  • test/python/fe_api/dsa/test_DSA_mxfp8_scale_utils.py
🚧 Files skipped from review as they are similar to previous changes (18)
  • python/cudnn/deepseek_sparse_attention/indexer_forward/indexer_fwd_sm100_mxfp8.py
  • python/cudnn/deepseek_sparse_attention/indexer_forward/indexer_fwd_sm100.py
  • python/cudnn/deepseek_sparse_attention/init.py
  • python/cudnn/deepseek_sparse_attention/score_recompute/indexer_score_unified_sm100.py
  • python/cudnn/deepseek_sparse_attention/utils/tensor_conversion.py
  • python/cudnn/deepseek_sparse_attention/indexer_top_k/api.py
  • python/cudnn/deepseek_sparse_attention/utils/runtime.py
  • test/python/fe_api/dsa/dsa_reference.py
  • python/cudnn/deepseek_sparse_attention/indexer_backward/api.py
  • test/python/fe_api/dsa/dsa_utils.py
  • python/cudnn/deepseek_sparse_attention/score_recompute/api.py
  • python/cudnn/deepseek_sparse_attention/utils/sm100/gemm.py
  • python/cudnn/deepseek_sparse_attention/score_recompute/dense_score_recompute_sm100.py
  • python/cudnn/deepseek_sparse_attention/utils/sm100/mma_desc.py
  • python/cudnn/deepseek_sparse_attention/indexer_forward/_interface_sm90.py
  • python/cudnn/deepseek_sparse_attention/indexer_forward/_interface.py
  • docs/fe-oss-apis/dsa.md
  • python/cudnn/deepseek_sparse_attention/indexer_forward/api.py

Comment thread python/cudnn/deepseek_sparse_attention/indexer_forward/_compressed_top_k_sm100.py Outdated
sW_dtype = Float32 if self.use_fp8_scales else self.w_dtype
sW_struct = cute.struct.Align[cute.struct.MemRange[sW_dtype, self.tile_m], 128]
sKScale_struct = cute.struct.Align[cute.struct.MemRange[Float32, self.tile_n * self.kv_stages], 128]
sLseReduce_struct = cute.struct.Align[cute.struct.MemRange[Float32, 32], 128]

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.

🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

LSE reduction scratch is hard-coded to 32 floats instead of being derived from the tile geometry, overflowing for qhead_per_kvhead=16. _write_lse_from_local_accum needs 8 slots per q token per stage with a stage base of 0/16, so q_tokens_per_stage > 2 (qhpkv 16) writes past the 32-element buffer.

  • python/cudnn/deepseek_sparse_attention/indexer_forward/indexer_fwd_sm90.py#L134-L134: size sLseReduce_struct as 8 * self.q_tokens_per_tile (and derive lse_reduce_base from q_stage_idx * self.q_tokens_per_stage * 8 at the call sites), or reject compute_lse for qhpkv 16.
  • python/cudnn/deepseek_sparse_attention/indexer_forward/indexer_fwd_sm90.py#L1316-L1316: update the get_tensor layout to the same geometry-derived extent rather than the literal (32,).
📍 Affects 1 file
  • python/cudnn/deepseek_sparse_attention/indexer_forward/indexer_fwd_sm90.py#L134-L134 (this comment)
  • python/cudnn/deepseek_sparse_attention/indexer_forward/indexer_fwd_sm90.py#L1316-L1316
🤖 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 `@python/cudnn/deepseek_sparse_attention/indexer_forward/indexer_fwd_sm90.py`
at line 134, Resize sLseReduce_struct at line 134 to 8 * self.q_tokens_per_tile
and derive lse_reduce_base at each _write_lse_from_local_accum call from
q_stage_idx * self.q_tokens_per_stage * 8, preserving the existing stage
indexing. At line 1316, update get_tensor’s layout extent to the same
geometry-derived size instead of (32,); both sites must support
qhead_per_kvhead=16 without out-of-bounds writes.

Comment thread test/python/fe_api/dsa/test_DSA_indexer_forward_compressed.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