Skip to content

frost(sdpa): SM120 backward — all head sizes (≤256), d192/d256, non-compact layouts, deterministic dQ - #533

Merged
Adnios merged 9 commits into
NVIDIA:developfrom
Adnios:feat/sm120_sdpa_bwd_deterministic_dQ
Aug 11, 2026
Merged

frost(sdpa): SM120 backward — all head sizes (≤256), d192/d256, non-compact layouts, deterministic dQ#533
Adnios merged 9 commits into
NVIDIA:developfrom
Adnios:feat/sm120_sdpa_bwd_deterministic_dQ

Conversation

@Adnios

@Adnios Adnios commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

Before submitting

  • I agree to license this contribution under the terms of LICENSE.txt.
  • I ran pre-commit run and committed any formatting changes.
  • I added GitHub labels: one cat-*, one or more mod-*, and one orig-* (see label list).

Affected area

  • FE OSS kernels or CuTeDSL
  • Documentation or samples

Summary

Extends the sdpa_bwd_sm120 FROST engine:

  1. Non-compact (dense_flex) layouts. Q/K/V/O/dO/dQ/dK/dV no longer must be BSHD-physical: any dense layout with the head dim innermost-contiguous (non-broadcast, non-overlapping; padded strides allowed) is accepted
  2. Native d192 / d256. New tile configs (q32 × kv64)
  3. Arbitrary head sizes. Any D that is a multiple of 8 up to 256 is served by zero-padding to the next supported size (32/64/128/192/256) via the staging copies.
  4. Deterministice dQ: deterministic=True serializes the per-(batch, head,q_tile) additions in ascending KV-tile order through a GMEM turn-counter array
  5. Add docs/fe-oss-apis/attention/sdpa_bwd_sm120.md

Why

Related issues

#381

API and compatibility impact

Testing

graphs on FROST engines: 488/2040 (23.9%) -- transition goal is all-FROST
  frost:sdpa_bwd_sm120: 7
  frost:sdpa_fwd_prefill_sm120: 481
  native:fp16-bwd: 185
  native:fp16-fwd: 1233
  native:fp8-fwd: 134

Summary by CodeRabbit

New Features

  • Added experimental SDPA backward support for SM120/SM121.
  • Added deterministic execution for reproducible results.
  • Expanded supported head dimensions up to 256, including padded dimensions.
  • Added flexible dense layouts and BHSD-contiguous input support.
  • Improved masking, workspace staging, and large-dimension handling.

Documentation

  • Documented API usage, integration options, supported layouts, constraints, and configuration.

Tests

  • Added coverage for deterministic execution, padded dimensions, flexible layouts, masks, and large head dimensions.

@Adnios Adnios self-assigned this Aug 10, 2026
@Adnios Adnios added cat-feature Requests for new functionality, APIs, examples, or behavior improvements. orig-nv-eng Reported or requested by NVIDIA engineering. mod-frost labels Aug 10, 2026
@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

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: 3644a420-cf92-44af-a4f6-0c393497c5b7

📥 Commits

Reviewing files that changed from the base of the PR and between 6c9c805 and 89b5c16.

📒 Files selected for processing (3)
  • docs/fe-oss-apis/overview.md
  • python/cudnn/sdpa/graph_analyzer.py
  • test/python/sdpa/frost/test_sdpa_graph_analyzer.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • docs/fe-oss-apis/overview.md
  • python/cudnn/sdpa/graph_analyzer.py
  • test/python/sdpa/frost/test_sdpa_graph_analyzer.py

📝 Walkthrough

Walkthrough

SM120/SM121 SDPA backward support now includes deterministic execution, dense-flex layouts, padded head dimensions through 256, workspace-backed staging, capacity-aware buffering, expanded tests, and API documentation.

Changes

SM120 SDPA backward

Layer / File(s) Summary
Contracts and engine geometry
python/cudnn/sdpa/bwd/config_sm120.py, python/cudnn/sdpa/graph_analyzer.py, python/cudnn/sdpa/bwd/engines.py
The engine accepts deterministic execution, dense-flex layouts, and head dimensions divisible by eight through 256. Lowering uses each analyzed port’s dimensions and strides.
API staging and workspace
python/cudnn/sdpa/bwd/api_dsl.py
The DSL API validates flexible layouts, pads unsupported dimensions, stages tensors in workspace, allocates dq_accum and dq_sem, and propagates deterministic mode through wrapper caching.
Deterministic kernel and buffering
python/cudnn/sdpa/bwd/kernels/bprop_f16_sm120.py
The kernel adds ordered dQ accumulation, relay-counter synchronization, dQ scatter helpers, dimensions 192 and 256, and single- or double-buffered Q staging.
Validation and documentation
test/python/sdpa/frost/*, docs/fe-oss-apis/attention/sdpa_bwd_sm120.md, docs/fe-oss-apis/overview.md
Tests cover padded dimensions, dense-flex layouts, deterministic numeric and bitwise behavior, and analyzer eligibility. Documentation describes the API, execution flow, masks, workspace, and constraints.

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

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant sdpa_bwd_wrapper_dsl_sm120
  participant SdpaBwdDsl
  participant SM120FusedMultiHeadAttentionFP16Backward
  participant Workspace
  Client->>sdpa_bwd_wrapper_dsl_sm120: submit tensors and deterministic option
  sdpa_bwd_wrapper_dsl_sm120->>SdpaBwdDsl: validate layouts and select padded dimension
  SdpaBwdDsl->>Workspace: allocate staging, dq_accum, and dq_sem
  SdpaBwdDsl->>SM120FusedMultiHeadAttentionFP16Backward: launch three-kernel backward chain
  SM120FusedMultiHeadAttentionFP16Backward->>Workspace: accumulate dQ and write dK/dV
  SdpaBwdDsl-->>Client: scatter staged gradients
Loading

Suggested labels: mod-cutedsl

Suggested reviewers: anerudhan, vedaanta

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description includes the checklist, affected areas, summary, issue, and a test count, but leaves Why and API impact blank and lacks exact test commands and results. Complete the Why, API and compatibility impact, and Testing sections with rationale, public-impact details, exact commands, and results.
Docstring Coverage ⚠️ Warning Docstring coverage is 57.14% 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 clearly summarizes the main SM120 SDPA backward changes, including expanded head sizes, flexible layouts, and deterministic dQ.
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.

@Adnios

Adnios commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator Author

@cudnn-ci-bot run frost

@cudnn-ci-bot

Copy link
Copy Markdown

🚀 Running mirror pipeline

Branch: cudnn-gh/pr-533-c1593cb
Pipeline: 61900837
Targets: frost

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (8)
docs/fe-oss-apis/attention/sdpa_bwd_sm120.md (2)

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

The GEMM4 notation disagrees with the kernel docstring.

This line states GEMM4 dQ = dS · K. The helper docstring in python/cudnn/sdpa/bwd/kernels/bprop_f16_sm120.py at line 288 states acc_dq = dS @ K^T.

For dS of shape (S_q, S_kv) and K of shape (S_kv, D), the correct product is dS · K, which matches this document. Correct the kernel docstring instead.

📝 Proposed fix in the kernel file
-    """GEMM 4: acc_dq = dS @ K^T (reads only sdS/sK, never sQ)."""
+    """GEMM 4: acc_dq = dS @ K (reads only sdS/sK, never sQ)."""
🤖 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 `@docs/fe-oss-apis/attention/sdpa_bwd_sm120.md` at line 92, Update the helper
docstring in the bprop_f16_sm120.py kernel around acc_dq to state that acc_dq =
dS @ K, matching the documented tensor shapes and GEMM4 notation; leave the
attention documentation unchanged.

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

Add a language to the two fenced code blocks.

markdownlint reports MD040 for both fences. Use text for the pipeline diagrams.

📝 Proposed fix
-```
+```text
 dot   delta = rowsum(O ∘ dO); zeroes dq_accum (and, when deterministic, the relay counters)
-```
+```text
 GEMM1  S  = Q · Kᵀ            (K streamed from SMEM)

Also applies to: 86-86

🤖 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 `@docs/fe-oss-apis/attention/sdpa_bwd_sm120.md` at line 74, Specify the
language for both fenced code blocks in the attention backward documentation by
changing their opening fences to use text, including the pipeline-diagram block
around dot and delta and the block around GEMM1 and S.

Source: Linters/SAST tools

python/cudnn/sdpa/bwd/kernels/bprop_f16_sm120.py (2)

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

The SWA turn derivation is correct; add the exact-multiple case to the comment.

det_turn = n_block - max((m_block * M + diag_off - W) // N, 0) reproduces the first visiting KV tile. The derivation holds for both the exact-multiple and the remainder cases, and negative values clamp to 0 under either truncating or flooring integer division.

The comment states the formula but not why the visitor set is contiguous. Contiguity follows because m_block_max(n) and m_block_min(n) are both non-decreasing in n, so a fixed m_block sees an interval of n. Recording that fact prevents a later change to the loop bounds from silently breaking the relay.

🤖 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/sdpa/bwd/kernels/bprop_f16_sm120.py` around lines 1030 - 1042,
Update the SWA derivation comment near det_turn to state that the visitor KV
tiles form a contiguous interval because m_block_max(n) and m_block_min(n) are
non-decreasing in n, covering both exact-multiple and remainder cases. Keep the
det_turn calculation unchanged.

389-428: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Document the relay’s CTA-scheduling precondition. CUDA does not guarantee CTA scheduling order, so _bwd_det_wait can deadlock if a lower n_block CTA is not resident or complete. Document this launch constraint. barrier_id=6 orders the preceding red.global.add operations before lane 0’s GPU-scope st.release; the PTX rule that red does not form acquire patterns does not invalidate this pattern.

🤖 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/sdpa/bwd/kernels/bprop_f16_sm120.py` around lines 389 - 428,
Document the deterministic relay launch precondition near
_bwd_det_wait/_bwd_det_release: CTAs must be scheduled so lower n_block CTAs are
resident or complete before higher ones wait, since CUDA does not guarantee CTA
scheduling order and otherwise the relay may deadlock. Preserve the existing
synchronization explanation, including that barrier_id=6 orders prior
red.global.add operations before lane 0’s GPU-scope release and that red’s lack
of acquire patterns does not invalidate this ordering.
python/cudnn/sdpa/bwd/engines.py (1)

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

Fix the comment wording and consider an envelope-style check.

The comment reads "Any head size multipled of 8". The correct wording is "Any head size that is a multiple of 8".

Also consider matching the forward row's d_envelope pattern (python/cudnn/sdpa/fwd/engines.py), which checks d <= cap and d % 8 == 0 and produces a short reason string. The enumerated set makes the mismatch message print 32 values.

♻️ Comment fix
-            # Any head size multipled of 8
+            # Any head size that is a multiple of 8, up to the largest native bin
             d=frozenset(range(8, max(_SM120_HEAD_DIMS) + 1, 8)),
🤖 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/sdpa/bwd/engines.py` around lines 243 - 244, Correct the comment
above the backward `d` constraint to say “Any head size that is a multiple of
8.” Replace the enumerated `frozenset(range(...))` constraint with an
envelope-style check matching the forward `d_envelope` pattern: accept
dimensions with `d <= max(_SM120_HEAD_DIMS)` and `d % 8 == 0`, and return a
concise reason string.
test/python/sdpa/frost/test_sdpa_bwd_dsl_sm120.py (2)

389-392: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Move the large parameter sweeps out of L0.

These new tests add roughly 30 L0 cases. Several compile a distinct CuTe DSL specialization per parameter combination, and the bitwise tests execute three full graph runs at s_q = 1024 with D up to 256. CuTe DSL compilation dominates the runtime of each new specialization.

Keep one representative case per code path at L0 and move the sweeps to L1 or higher. Suggested split:

  • Keep at L0: one large_d_wrapper case, one padded_head_dim case, one deterministic_bitwise case, and deterministic_large_d_numeric (it covers the Q_STAGES == 1 branch).
  • Move to L1: the remaining head_dim and mask combinations of test_sdpa_bwd_dsl_sm120_large_d_wrapper, test_sdpa_bwd_dsl_sm120_padded_head_dim, test_sdpa_bwd_dsl_sm120_deterministic_bitwise, and test_sdpa_bwd_dsl_sm120_deterministic_large_d_bitwise.

As per path instructions: "Mark every new Python test with a level from L0 through L4; keep L0 tests fast and place large parameter sweeps at higher levels."

Also applies to: 436-438, 536-539, 594-599

🤖 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/sdpa/frost/test_sdpa_bwd_dsl_sm120.py` around lines 389 - 392,
Reduce the new SM120 test parameter sweeps marked L0: retain only one
representative case for large_d_wrapper, padded_head_dim, deterministic_bitwise,
and deterministic_large_d_numeric, while moving the remaining head_dim/mask
combinations in test_sdpa_bwd_dsl_sm120_large_d_wrapper,
test_sdpa_bwd_dsl_sm120_padded_head_dim,
test_sdpa_bwd_dsl_sm120_deterministic_bitwise, and
test_sdpa_bwd_dsl_sm120_deterministic_large_d_bitwise to L1 or higher.

Source: Path instructions


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

Add a negative control to the bitwise test.

_run_bitwise_case asserts that three deterministic runs match bitwise. The assertion also passes if the non-deterministic path happens to be stable for the chosen shape, so it does not prove that deterministic=True changed anything.

Consider adding one case that runs with deterministic=False on a shape with many KV tiles per q-tile and records the result. If that case is also stable in CI, the deterministic assertion carries no signal and the shape should be enlarged. This is a test-strength improvement, not a defect.

🤖 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/sdpa/frost/test_sdpa_bwd_dsl_sm120.py` around lines 505 - 533,
Add a negative-control execution to _run_bitwise_case using deterministic=False
on a shape with many KV tiles per q-tile, record its outputs across runs, and
verify whether they remain bitwise stable. Ensure the selected case is enlarged
if the nondeterministic path is consistently stable in CI, while preserving the
existing deterministic=True assertions.
test/python/sdpa/frost/test_sdpa_graph_analyzer.py (1)

952-956: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a positive assertion for an accepted non-native head dimension.

The test now asserts that d=100 and d=264 are rejected. It does not assert that a multiple of 8 inside the envelope but outside the native bins is accepted. That is the new behavior this PR introduces at the analyzer layer.

♻️ Suggested addition
     monkeypatch.setattr(ga, "_device_cc", lambda: (12, 0))
+    # Inside the envelope and a multiple of 8: accepted (the adapter pads to the next bin).
+    assert _BWD_ENGINE in _bwd_eligible(_mk_bwd_graph(d=40))
+    assert _BWD_ENGINE in _bwd_eligible(_mk_bwd_graph(d=200))
     assert not _bwd_eligible(_mk_bwd_graph(d=100))
     assert not _bwd_eligible(_mk_bwd_graph(d=264))
🤖 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/sdpa/frost/test_sdpa_graph_analyzer.py` around lines 952 - 956,
Add a positive assertion in test_bwd_probe_rejects_unsupported_head_dim using an
accepted non-native head dimension, such as d=104, which is a multiple of 8
within the adapter’s supported envelope. Keep the existing rejection assertions
for d=100 and d=264.
🤖 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 `@docs/fe-oss-apis/attention/sdpa_bwd_sm120.md`:
- Line 15: Add cudnn.sdpa.bwd.sdpa_bwd_wrapper_dsl_sm120 to the lazy-export
table in cudnn.__init__ while preserving lazy loading; reference the module and
symbol without eagerly importing torch or cutlass.

---

Nitpick comments:
In `@docs/fe-oss-apis/attention/sdpa_bwd_sm120.md`:
- Line 92: Update the helper docstring in the bprop_f16_sm120.py kernel around
acc_dq to state that acc_dq = dS @ K, matching the documented tensor shapes and
GEMM4 notation; leave the attention documentation unchanged.
- Line 74: Specify the language for both fenced code blocks in the attention
backward documentation by changing their opening fences to use text, including
the pipeline-diagram block around dot and delta and the block around GEMM1 and
S.

In `@python/cudnn/sdpa/bwd/engines.py`:
- Around line 243-244: Correct the comment above the backward `d` constraint to
say “Any head size that is a multiple of 8.” Replace the enumerated
`frozenset(range(...))` constraint with an envelope-style check matching the
forward `d_envelope` pattern: accept dimensions with `d <=
max(_SM120_HEAD_DIMS)` and `d % 8 == 0`, and return a concise reason string.

In `@python/cudnn/sdpa/bwd/kernels/bprop_f16_sm120.py`:
- Around line 1030-1042: Update the SWA derivation comment near det_turn to
state that the visitor KV tiles form a contiguous interval because
m_block_max(n) and m_block_min(n) are non-decreasing in n, covering both
exact-multiple and remainder cases. Keep the det_turn calculation unchanged.
- Around line 389-428: Document the deterministic relay launch precondition near
_bwd_det_wait/_bwd_det_release: CTAs must be scheduled so lower n_block CTAs are
resident or complete before higher ones wait, since CUDA does not guarantee CTA
scheduling order and otherwise the relay may deadlock. Preserve the existing
synchronization explanation, including that barrier_id=6 orders prior
red.global.add operations before lane 0’s GPU-scope release and that red’s lack
of acquire patterns does not invalidate this ordering.

In `@test/python/sdpa/frost/test_sdpa_bwd_dsl_sm120.py`:
- Around line 389-392: Reduce the new SM120 test parameter sweeps marked L0:
retain only one representative case for large_d_wrapper, padded_head_dim,
deterministic_bitwise, and deterministic_large_d_numeric, while moving the
remaining head_dim/mask combinations in test_sdpa_bwd_dsl_sm120_large_d_wrapper,
test_sdpa_bwd_dsl_sm120_padded_head_dim,
test_sdpa_bwd_dsl_sm120_deterministic_bitwise, and
test_sdpa_bwd_dsl_sm120_deterministic_large_d_bitwise to L1 or higher.
- Around line 505-533: Add a negative-control execution to _run_bitwise_case
using deterministic=False on a shape with many KV tiles per q-tile, record its
outputs across runs, and verify whether they remain bitwise stable. Ensure the
selected case is enlarged if the nondeterministic path is consistently stable in
CI, while preserving the existing deterministic=True assertions.

In `@test/python/sdpa/frost/test_sdpa_graph_analyzer.py`:
- Around line 952-956: Add a positive assertion in
test_bwd_probe_rejects_unsupported_head_dim using an accepted non-native head
dimension, such as d=104, which is a multiple of 8 within the adapter’s
supported envelope. Keep the existing rejection assertions for d=100 and d=264.
🪄 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: 920e811f-f9ce-4dea-8ada-c01c4997c0e2

📥 Commits

Reviewing files that changed from the base of the PR and between 3fcee36 and c1593cb.

📒 Files selected for processing (9)
  • docs/fe-oss-apis/attention/sdpa_bwd_sm120.md
  • docs/fe-oss-apis/overview.md
  • python/cudnn/sdpa/bwd/api_dsl.py
  • python/cudnn/sdpa/bwd/config_sm120.py
  • python/cudnn/sdpa/bwd/engines.py
  • python/cudnn/sdpa/bwd/kernels/bprop_f16_sm120.py
  • python/cudnn/sdpa/graph_analyzer.py
  • test/python/sdpa/frost/test_sdpa_bwd_dsl_sm120.py
  • test/python/sdpa/frost/test_sdpa_graph_analyzer.py

Comment thread docs/fe-oss-apis/attention/sdpa_bwd_sm120.md Outdated
@Adnios

Adnios commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator Author

@cudnn-ci-bot run frost

@cudnn-ci-bot

Copy link
Copy Markdown

🚀 Running mirror pipeline

Branch: cudnn-gh/pr-533-2f1a661
Pipeline: 61903220
Targets: frost

Comment thread python/cudnn/sdpa/graph_analyzer.py
@Adnios

Adnios commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator Author

@cudnn-ci-bot run frost

@cudnn-ci-bot

Copy link
Copy Markdown

🚀 Running mirror pipeline

Branch: cudnn-gh/pr-533-6c9c805
Pipeline: 61972558
Targets: frost

@Adnios

Adnios commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator Author

@cudnn-ci-bot run frost

@cudnn-ci-bot

Copy link
Copy Markdown

🚀 Running mirror pipeline

Branch: cudnn-gh/pr-533-89b5c16
Pipeline: 62063157
Targets: frost

@Adnios
Adnios merged commit 60e2ec5 into NVIDIA:develop Aug 11, 2026
1 check passed
egilliam-nv added a commit to egilliam-nv/cudnn-frontend that referenced this pull request Aug 12, 2026
…ced its own copy)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
YangXu1990uiuc pushed a commit that referenced this pull request Aug 13, 2026
* SM80 (A100) SDPA: FROST engines + cudnn.sdpa adapters

CuTe-DSL SDPA forward and backward for SM80 as FROST engines, plus
standalone cudnn.sdpa APIs.

* sdpa_fwd_prefill_sm80 joins the FrostSdpaFwdEngines family (the manifest
  row's sm_lo drops to 80); sdpa_bwd_sm80 introduces the first backward
  opset as a new FrostSdpaBwdEngines family on the reserved
  FROST_SDPA_BWD_ID_BASE block, with a frost_sdpa_bwd manifest row anchored
  on SDPA_BWD.
* The shared graph_analyzer learns sdpa_backward() graphs: backward facts,
  K/V transposed-input-view canonicalization, and a forward-direction gate
  in the shared mismatch().
* Kernels (fwd generic + d256; bwd generic + d64 fast path) build on the
  shared frost/tile_dsl library; torch-native host code, per-shape
  self-caching, stream-aware and CUDA-graph-capturable.
* Standalone SdpafwdSm80 / SdpabwdSm80 APIBase adapters + wrappers,
  including a packed-THD path the engines do not expose yet.
* Docs: FE OSS API pages + Attention.md sections.

Verified on A100: reference suites (103), engine/analyzer/stream suites
(123), and full test_mhas_v2 with FROST auto-selection: 1268 passed / 0
failed, 41.2% of graphs served on FROST.

The kernels originate from earlier internal work by Roman Anders.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* review: address CodeRabbit findings

* drop the stray fe_cuda_13.3.cfg (local build config, added by accident)
* THD forward: resolve the default softmax scale from the user's head dim
  BEFORE flavor padding (a d=96 call silently used 1/sqrt(128))
* THD forward/backward: reject dense-only features (bias / RoPE /
  block_mask / seq lens / scale_output / scheduler) instead of silently
  computing without them; drop the never-used backward max_s_q kwarg
* dense mask resolution: window_size=(-1, r) without is_causal is now
  rejected instead of silently selecting a 0-token SWA window
* bprop kernel: assert K's head dim matches Q's, and reject RoPE at
  d_qk > 128 (the sDQ SMEM staging exceeds the A100 budget beyond that)
* bwd reference in the fe_api suite anchors the causal diagonal top-left,
  matching the mask the wrapper actually requests
* docs: requirements sections no longer cite the retired ctm package;
  provenance notes restored in both kernel packages; THD feature gating
  documented
* stale comments: flavor envelope (dsv3->qwen), d64 'not yet routed',
  gptoss draft artifact, prefill header diagram / swizzle note /
  mainloop wait counts, d256 wait count

* review: actually drop the stray fe_cuda_13.3.cfg

The previous commit unstaged it, then a blanket git add -A swept the
untracked local file back in before committing. Now excluded locally.

* review: round 2 — backward twins of the round-1 fixes + test tiering

* bwd dense mask resolution: reject window_size=(-1, r) without is_causal
  instead of silently selecting a 0-token SWA window (the fwd adapter and
  both THD paths already resolve it this way)
* bwd THD: resolve the default softmax scale from the user's head dim
  BEFORE flavor padding (same silent-wrong-gradients bug as the fwd twin)
* fe_api sweeps (48 cases each) move from L0 to L2 per the repo guideline;
  a single representative smoke case stays at L0 for each direction
* underscore the unused unpacks Ruff flags in the fwd reference

* docs: purge the last ctm mentions — the retired DSL package is not a dependency of anything in this PR

* test: skip the SM80 fe_api suites when the CuTe DSL is missing or predates cutlass.experimental

The package imports are lazy (PEP 562) since the engine-family cleanup, so
a missing or old nvidia-cutlass-dsl no longer fails at wrapper import —
it erupts at kernel-load time mid-test. The oss:rel CI leg (older DSL)
showed 9 such errors; probe cutlass.experimental in the module skip so
those environments skip cleanly.

* review: round 3 — require the bound seq_len_q buffer + Ruff lints

* resolve_feature_operands: a graph that BINDS seq_len_q must get its
  buffer through _need() like every other feature operand — silently
  omitting it would execute a different query-length contract (missed
  BR-under-padding base and padded-row LSE trim)
* Ruff RUF059 (two unused unpacks) and E731 (lambda-to-def)

* fix: drop duplicated stale helpers the analyzer merge left behind

The rebase onto the engine-family cleanup appended our helper block
including copies of resolve_variant_pack (identical, harmless) and
tensor_desc_from_ir (STALE: still referencing the deleted
_DTYPE_FROM_CUDNN map). The stale copy shadowed upstream's fixed one and
took down every SM100/SM120 lowering with a NameError — invisible on
A100, where those paths skip; pipeline 61601513's Blackwell frost leg
caught it (716 failures).

* fix: never wrap the default stream handle in ExternalStream (CI determinism zeros)

Root cause of the frost_tests:sdpa[Ampere] determinism failures (104/104
is_determin backward configs, second execution returning all-zero grads):
the harness's cudnn handle carries raw stream 0, and _stream_ctx wrapped it
in torch.cuda.ExternalStream(0). On the CI image's NGC torch build
(2.12.0a0), every kernel launch inside that context after the compile run
silently no-ops. Reproduced and verified in the CI container itself
(gitlab/cudnn_frontend:cudnn_13.3.0 + the pipeline's build artifact):
before — run 0 correct, runs 1+ all-zero; after — bitwise-identical runs,
test_sdpa_random_bwd_L0 176 passed / 0 failed under -n 4.

_stream_ctx now maps a raw handle equal to torch's current/default stream
onto that torch stream object and reserves ExternalStream for genuine
foreign streams — the same guard fwd/api_dsl._torch_stream_context and
gemm/cutedsl/grouped/backend_utils.py already carry (these adapters were
the only unguarded spot in the tree).

Known residual, unrelated to CI: on NGC torch the FIRST execute after
re-pointing a handle to a brand-new stream still no-ops once on a cached
kernel (suspected DSL/tvm-ffi launch-state caching; to be reported
upstream — the kernels cannot compile without tvm-ffi, so it could not be
isolated further).

* test: pin SM80 plans via frost_test_utils.select_engine (post-#528 plan names carry knobs)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* review: fold SM80 adapters into api.py, configs into config_sm80.py, drop the docs pages

Per maintainer feedback on the PR:
- SdpafwdSm80/SdpabwdSm80 + wrappers move from api_sm80.py into each opset's
  api.py, following the SM100 classes there (one api.py per opset, no per-arch
  files). Lazy exports and the engine lowerings repoint; no signature changes.
- The per-flavor kernel configs leave kernels/ for parent-level config_sm80.py
  (one per direction), matching config_sm100/config_sm120.
- The FE OSS docs pages and their overview/Attention/llms.txt entries are
  dropped for now; the engines remain the PR's product.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* rebase: dedupe the bwd Capabilities.layouts field (#533 introduced its own copy)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cat-feature Requests for new functionality, APIs, examples, or behavior improvements. mod-frost orig-nv-eng Reported or requested by NVIDIA engineering.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants