Skip to content

Add SM120 FROST SDPA backward engine (sdpa_bwd_sm120) - #486

Merged
Aneureka merged 7 commits into
NVIDIA:developfrom
Adnios:feat/sm120_sdpa_bwd
Aug 6, 2026
Merged

Add SM120 FROST SDPA backward engine (sdpa_bwd_sm120)#486
Aneureka merged 7 commits into
NVIDIA:developfrom
Adnios:feat/sm120_sdpa_bwd

Conversation

@Adnios

@Adnios Adnios commented Aug 5, 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.

Affected area

  • FE OSS kernels or CuTeDSL

Summary

Three-kernel chain (dot_do_o → main 5-GEMM KV-stationary kernel → convert_dq),
PDL-linked, 12 warps (8 compute + 1 TMA producer), dQ accumulated through fp32
global atomics.

  • currently only support:
    • head = 32, 64, 128
    • dense / bottom-right causal
    • knob q/kv_tile = 64 or 128

Why

Related issues

Related to #381

API and compatibility impact

Testing

  • test_sdpa_graph_analyzer.py: 63 passed (14 new GPU-free bwd probe/facts tests)
  • test_sdpa_bwd_dsl_sm120.py (new): 14 passed
  • test_mhas_v2.py::test_sdpa_random_bwd_L0 with the engine enabled:
    165 passed, 24.1% of graphs routed to FROST, zero numeric failures
    (14 OOMs reproduce identically with FROST disabled — pre-existing 32 GB capacity issue)

Summary by CodeRabbit

New Features

  • Added optimized SDPA backward support for SM120/SM121 GPUs.
  • Supports FP16 and BF16, causal attention, multiple head dimensions, configurable tiling, and fused dQ, dK, and dV computation.
  • Added automatic engine selection, workspace handling, stream support, and shape-specialized execution.
  • Expanded graph analysis to recognize and validate backward SDPA operations.

Bug Fixes

  • Improved separation of forward- and backward-only engine eligibility checks.

Tests

  • Added comprehensive coverage for gradients, causal modes, layouts, sequence sizes, data types, and engine routing.

@coderabbitai

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

Walkthrough

Changes

SM120/SM121 FROST SDPA backward support now includes graph analysis, capability routing, DSL execution, fused dQ/dK/dV kernels, manifest registration, shared tile-DSL helpers, and validation.

SDPA backward support

Layer / File(s) Summary
Backward graph analysis and engine routing
python/cudnn/sdpa/graph_analyzer.py, python/cudnn/sdpa/bwd/engines.py, python/cudnn/sdpa/fwd/engines.py, python/cudnn/engines/*
Backward tensors and features are extracted and validated. Supported graphs route to the SM120 engine.
Backward DSL adapter and specialization
python/cudnn/sdpa/bwd/api_dsl.py, python/cudnn/sdpa/bwd/config_sm120.py, python/cudnn/sdpa/bwd/__init__.py
The adapter validates inputs, compiles specialized kernels, manages workspace, caches specializations, and returns dq, dk, and dv.
SM120 fused backward kernels
python/cudnn/sdpa/bwd/kernels/*, python/cudnn/frost/tile_dsl/mma.py, python/cudnn/frost/tile_dsl/swizzle.py, python/cudnn/sdpa/fwd/kernels/prefill_f16_sm120.py
Fused FP16/BF16 kernels compute backward gradients. Shared MMA and swizzle helpers support backward and forward kernels.
Backward validation coverage
test/python/sdpa/frost/test_sdpa_graph_analyzer.py, test/python/sdpa/frost/test_sdpa_bwd_dsl_sm120.py
Tests cover graph facts, capability diagnostics, routing, workspace, causal variants, sequence tails, and tile paths.

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

Sequence Diagram(s)

sequenceDiagram
  participant Graph
  participant Engine
  participant DSL
  participant Kernel
  Graph->>Engine: analyze backward tensors and features
  Engine->>DSL: lower and compile SM120 plan
  DSL->>Kernel: launch dot, main, and dQ conversion kernels
  Kernel-->>DSL: write dQ, dK, and dV
  DSL-->>Engine: return gradients and workspace state
Loading

Possibly related PRs

Suggested labels: cat-feature, orig-nv-eng

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 48.51% 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
Title check ✅ Passed The title clearly identifies the addition of the SM120 FROST SDPA backward engine.
Description check ✅ Passed The description covers the affected area, summary, related issue, testing results, and submission checklist, but leaves Why and API compatibility unanswered.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🧹 Nitpick comments (6)
python/cudnn/engines/manifest.py (1)

180-191: 📐 Maintainability & Code Quality | 🔵 Trivial

Row is consistent with the reserved ID block and the SM encoding.

id_hi = FROST_SDPA_BWD_ID_BASE + 100 makes the row own 20_400..20_499, which matches the engine_ids.py comment, and it does not overlap the forward block 20_300..20_399. sm_lo=120 / sm_hi=121 follows the major * 10 + minor convention used by the frost_gemm row.

Line 187 records a TODO to widen the architecture bounds when an SM100 or SM80 spec lands. Do you want me to open an issue to track it?

🤖 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/engines/manifest.py` around lines 180 - 191, Retain the
FrostSdpaBwdEngines row as implemented; no code change is required. The reserved
ID range and SM encoding are consistent, and the TODO in the FrostSdpaBwd
configuration may remain until SM100 or SM80 specifications are available.
python/cudnn/sdpa/graph_analyzer.py (1)

211-221: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Update the docstring to cover backward nodes.

Line 220 now accepts SDPA_BWD, but the docstring still describes only an SDPA-forward node. The predicate is shared by the forward and backward engine registries, so the stale text misstates the routing contract.

♻️ Proposed docstring fix
-    """The graph's sole SDPA-forward node, or None if the graph is anything else."""
+    """The graph's sole SDPA node (forward, backward, MXFP8 or FP8), or None
+    if the graph is anything else."""
🤖 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/graph_analyzer.py` around lines 211 - 221, Update the
_single_sdpa_node docstring to describe the graph’s sole supported SDPA node,
including both forward and backward variants accepted by the node_type
predicate. Keep the routing behavior unchanged.
test/python/sdpa/frost/test_sdpa_graph_analyzer.py (1)

825-827: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

bias=True sets both bias and dBias, so this test does not isolate dBias.

_mk_bwd_graph(bias=True) adds a bias input and a dBias output. In mismatch() the has_dbias gate runs before the has_bias gate, so the rejection could come from either capability. Split the helper flag into bias and dbias to cover the two gates separately.

♻️ Proposed split of the bias flag
-    bias: bool = False,
+    bias: bool = False,
+    dbias: bool = False,
     **bwd_kwargs,
 ):
@@
-    if bias:
+    if bias or dbias:
         bias_t = g.tensor(dim=(1, H, s_q, s_kv), stride=(H * s_q * s_kv, s_q * s_kv, s_kv, 1), data_type=DTYPE, name="bias")
-        dbias_t = g.tensor(dim=(1, H, s_q, s_kv), stride=(H * s_q * s_kv, s_q * s_kv, s_kv, 1), data_type=DTYPE, name="dBias")
-        bwd_kwargs.update(bias=bias_t, dBias=dbias_t)
+        bwd_kwargs.update(bias=bias_t)
+        if dbias:
+            dbias_t = g.tensor(dim=(1, H, s_q, s_kv), stride=(H * s_q * s_kv, s_q * s_kv, s_kv, 1), data_type=DTYPE, name="dBias")
+            bwd_kwargs.update(dBias=dbias_t)
 def test_bwd_probe_rejects_dbias(monkeypatch):
     monkeypatch.setattr(ga, "_device_cc", lambda: (12, 0))
-    assert not _bwd_eligible(_mk_bwd_graph(bias=True))
+    assert not _bwd_eligible(_mk_bwd_graph(bias=True, dbias=True))
+    assert not _bwd_eligible(_mk_bwd_graph(bias=True))
🤖 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 825 - 827,
Update _mk_bwd_graph to accept independent bias and dbias flags, wiring them to
the bias input and dBias output respectively. Adjust
test_bwd_probe_rejects_dbias to enable only dbias, and add or update a separate
test to verify bias rejection with only bias enabled, so each mismatch() gate is
isolated.
test/python/sdpa/frost/test_sdpa_bwd_dsl_sm120.py (1)

173-178: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Move the unconditional skip to the test that triggers it.

_run_bwd_graph skips whenever q_tile or kv_tile is set. test_sdpa_bwd_dsl_sm120_tile_knobs always sets both, so both parameterizations always skip. The skip reason is hidden in a helper, and the helper builds the whole graph before it skips. Mark the test itself with @pytest.mark.skip and drop the q_tile/kv_tile plumbing from _run_bwd_graph and _run_case until the knob plans exist.

♻️ Proposed move of the skip to the test site
-    if q_tile is not None or kv_tile is not None:
-        pytest.skip(
-            "graph.set_engine_knobs() was removed with the monkey-patch dispatch layer and has no replacement in "
-            "this MR: knobs now ride on the plan (engines.base.PlanConfig.knobs), one ranked entry per knob set, "
-            "picked with select_plan(). Re-enable once the SDPA bwd family proposes its tile domain as plans."
-        )
-
     graph.validate()
 `@pytest.mark.L0`
+@pytest.mark.skip(
+    reason="graph.set_engine_knobs() was removed with the monkey-patch dispatch layer and has no replacement in "
+    "this MR: knobs now ride on the plan (engines.base.PlanConfig.knobs), one ranked entry per knob set, "
+    "picked with select_plan(). Re-enable once the SDPA bwd family proposes its tile domain as plans."
+)
 `@pytest.mark.parametrize`(
🤖 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 173 - 178,
Move the unconditional skip to test_sdpa_bwd_dsl_sm120_tile_knobs using
pytest.mark.skip with the existing reason, and remove the q_tile/kv_tile
parameters and related skip logic from _run_bwd_graph and _run_case. Keep
non-knob test paths unchanged while allowing the skipped test to be marked
before graph construction.
python/cudnn/sdpa/bwd/kernels/bprop_f16_sm120.py (2)

304-312: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Raise a clear error for an unsupported head_dim.

Line 304 indexes DEFAULT_TILES directly. An unsupported head_dim produces a bare KeyError. Every neighboring constraint in this constructor reports a descriptive ValueError (Line 312 and Line 329), and validate_params exists as a backstop for direct template use. Make this failure consistent.

♻️ Proposed refactor
+        if head_dim not in self.DEFAULT_TILES:
+            raise ValueError(f"head_dim must be one of {tuple(self.DEFAULT_TILES)}; got {head_dim}")
         self.q_tile, self.kv_tile = self.DEFAULT_TILES[head_dim]
🤖 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 304 - 312,
Update the constructor initialization around DEFAULT_TILES so an unsupported
head_dim is detected before direct dictionary indexing and raises a descriptive
ValueError instead of propagating KeyError. Preserve the existing tile overrides
and validation behavior for supported head dimensions, and keep validate_params
as the backstop for direct template use.

1176-1184: 🚀 Performance & Scalability | 🔵 Trivial

Consider a bound and a metric for the compile cache.

@lru_cache(maxsize=None) never evicts. Each entry holds three compiled CUDA modules for one (compute_capability, b, qh, sq, skv, d) tuple. A serving process that sees many distinct batch sizes and sequence lengths grows host and device memory for the lifetime of the process. The PR notes 14 OOMs at 32 GB attributed to a pre-existing capacity issue; an unbounded kernel cache adds to that pressure.

A bound here alone is not sufficient, because _wrapper_api_cache in python/cudnn/sdpa/bwd/api_dsl.py Line 369 is also unbounded and holds references to the compiled objects. Evicting one and not the other causes silent recompilation. Treat the cache size as one cross-layer decision, and export the entry count so operators can see the growth.

🤖 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 1176 - 1184,
Bound the compile cache used by compile and coordinate the same entry limit with
_wrapper_api_cache so evicting a kernel entry also releases its corresponding
wrapper references instead of triggering silent recompilation. Define the cache
capacity as a shared configurable/exported metric, expose the current entry
count for operators, and update both cache implementations to use that single
cross-layer limit.
🤖 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/sdpa/bwd/api_dsl.py`:
- Around line 105-110: Update _to_bshd and the output handling for dq_tensor,
dk_tensor, and dv_tensor so non-contiguous output views are rejected instead of
converted with contiguous(). Keep copying permitted for input tensors, but make
execute-time output validation fail clearly before the kernel writes, regardless
of cached descriptors or sample tensors.
- Around line 14-26: Add the SM120 backward API symbols SdpaBwdDslSm120 and
sdpa_bwd_wrapper_dsl_sm120 to the optional lazy-export mapping used by the cudnn
package, ensuring resolving those exports does not eagerly import api_dsl.py.
Document both exports under docs/fe-oss-apis/ and add pytest coverage under
test/python/fe_api/ verifying lazy resolution and the exported API names.

In `@python/cudnn/sdpa/bwd/engines.py`:
- Line 374: Sort the exports in the __all__ declaration alphabetically to
satisfy RUF022, preserving all existing names and their spelling.

In `@python/cudnn/sdpa/bwd/kernels/bprop_f16_sm120.py`:
- Around line 1-2: Align the SPDX license header in the bprop_f16_sm120 module
with the confirmed package license, matching the sibling files if MIT applies.
If the FlashAttention-2 attribution requires BSD-3-Clause coverage, preserve the
applicable package license and add explicit BSD-3-Clause attribution rather than
substituting Apache-2.0.

In `@python/cudnn/sdpa/graph_analyzer.py`:
- Around line 311-320: Update the backward K/V canonicalization block to detect
native (B, H, D, S) views using K/V stride ordering rather than only dimension
comparisons. In the is_backward path, adjust k_dim/k_stride and v_dim/v_stride
when their strides identify the transposed layout, including square cases where
S_kv equals d_qk or d_v, while preserving canonical BSHD dimensions and strides
for bshd_layout_ok.

In `@test/python/sdpa/frost/test_sdpa_bwd_dsl_sm120.py`:
- Around line 310-319: Make test_sdpa_bwd_dsl_sm120_stream_respect observably
verify stream usage instead of relying on _run_bwd_graph’s device-wide
synchronization. Add stream-ordering instrumentation, such as blocking stream
with a long-running kernel and checking the default stream remains complete, or
recording an event on stream and confirming the engine work is captured;
preserve the test’s no-default-stream-leak assertion.
- Around line 238-256: Update _run_case to assert that the selected-engine test
actually uses the FROST engine: when select=True, require plan_name to equal
ENGINE, alongside the existing workspace validation. Keep the numeric assertions
and behavior for non-selected runs unchanged.

---

Nitpick comments:
In `@python/cudnn/engines/manifest.py`:
- Around line 180-191: Retain the FrostSdpaBwdEngines row as implemented; no
code change is required. The reserved ID range and SM encoding are consistent,
and the TODO in the FrostSdpaBwd configuration may remain until SM100 or SM80
specifications are available.

In `@python/cudnn/sdpa/bwd/kernels/bprop_f16_sm120.py`:
- Around line 304-312: Update the constructor initialization around
DEFAULT_TILES so an unsupported head_dim is detected before direct dictionary
indexing and raises a descriptive ValueError instead of propagating KeyError.
Preserve the existing tile overrides and validation behavior for supported head
dimensions, and keep validate_params as the backstop for direct template use.
- Around line 1176-1184: Bound the compile cache used by compile and coordinate
the same entry limit with _wrapper_api_cache so evicting a kernel entry also
releases its corresponding wrapper references instead of triggering silent
recompilation. Define the cache capacity as a shared configurable/exported
metric, expose the current entry count for operators, and update both cache
implementations to use that single cross-layer limit.

In `@python/cudnn/sdpa/graph_analyzer.py`:
- Around line 211-221: Update the _single_sdpa_node docstring to describe the
graph’s sole supported SDPA node, including both forward and backward variants
accepted by the node_type predicate. Keep the routing behavior unchanged.

In `@test/python/sdpa/frost/test_sdpa_bwd_dsl_sm120.py`:
- Around line 173-178: Move the unconditional skip to
test_sdpa_bwd_dsl_sm120_tile_knobs using pytest.mark.skip with the existing
reason, and remove the q_tile/kv_tile parameters and related skip logic from
_run_bwd_graph and _run_case. Keep non-knob test paths unchanged while allowing
the skipped test to be marked before graph construction.

In `@test/python/sdpa/frost/test_sdpa_graph_analyzer.py`:
- Around line 825-827: Update _mk_bwd_graph to accept independent bias and dbias
flags, wiring them to the bias input and dBias output respectively. Adjust
test_bwd_probe_rejects_dbias to enable only dbias, and add or update a separate
test to verify bias rejection with only bias enabled, so each mismatch() gate is
isolated.
🪄 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: 0dbb453b-615a-42ee-85d7-230b33b50ef7

📥 Commits

Reviewing files that changed from the base of the PR and between b7ddaae and a4eb399.

📒 Files selected for processing (16)
  • python/cudnn/engines/engine_ids.py
  • python/cudnn/engines/manifest.py
  • python/cudnn/frost/tile_dsl/mma.py
  • python/cudnn/frost/tile_dsl/swizzle.py
  • python/cudnn/sdpa/bwd/__init__.py
  • python/cudnn/sdpa/bwd/api_dsl.py
  • python/cudnn/sdpa/bwd/config_sm120.py
  • python/cudnn/sdpa/bwd/engine.py
  • python/cudnn/sdpa/bwd/engines.py
  • python/cudnn/sdpa/bwd/kernels/__init__.py
  • python/cudnn/sdpa/bwd/kernels/bprop_f16_sm120.py
  • python/cudnn/sdpa/fwd/engines.py
  • python/cudnn/sdpa/fwd/kernels/prefill_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 python/cudnn/sdpa/bwd/api_dsl.py
Comment thread python/cudnn/sdpa/bwd/api_dsl.py
Comment thread python/cudnn/sdpa/bwd/engines.py Outdated
Comment thread python/cudnn/sdpa/bwd/kernels/bprop_f16_sm120.py Outdated
Comment thread python/cudnn/sdpa/graph_analyzer.py
Comment thread test/python/sdpa/frost/test_sdpa_bwd_dsl_sm120.py
Comment thread test/python/sdpa/frost/test_sdpa_bwd_dsl_sm120.py Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

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

Inline comments:
In `@test/python/sdpa/frost/test_sdpa_graph_analyzer.py`:
- Around line 833-835: Update test_bwd_probe_rejects_dbias to isolate the dBias
condition instead of relying on _mk_bwd_graph(dbias=True), which also adds bias.
Construct a dBias-only graph if supported, or assert the rejection diagnostic
specifically identifies dBias, ensuring the test fails when only bias causes
rejection.
🪄 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: 862e94eb-60f2-4385-90c8-dca15afe9c25

📥 Commits

Reviewing files that changed from the base of the PR and between a4eb399 and 5206133.

📒 Files selected for processing (6)
  • python/cudnn/sdpa/bwd/api_dsl.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
🚧 Files skipped from review as they are similar to previous changes (4)
  • python/cudnn/sdpa/bwd/api_dsl.py
  • python/cudnn/sdpa/bwd/kernels/bprop_f16_sm120.py
  • python/cudnn/sdpa/graph_analyzer.py
  • python/cudnn/sdpa/bwd/engines.py

Comment thread test/python/sdpa/frost/test_sdpa_graph_analyzer.py
@Adnios
Adnios force-pushed the feat/sm120_sdpa_bwd branch from b3a83ee to 48785e4 Compare August 5, 2026 08:42
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Note

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
python/cudnn/sdpa/bwd/api_dsl.py (1)

379-431: 🚀 Performance & Scalability | 🔵 Trivial | ⚖️ Poor tradeoff

_wrapper_api_cache grows without a bound.

The key contains the full shape, stride, dtype, and device signature of six tensors plus the causal flags and the scale. Each miss stores a SdpaBwdDslSm120 instance that owns compiled kernels. A workload with many distinct sequence lengths retains every specialization for the process lifetime. Consider a bounded cache with eviction, for example functools.lru_cache on a keyed factory or an explicit OrderedDict with a size limit.

🤖 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/api_dsl.py` around lines 379 - 431, Bound the
specialization cache used by sdpa_bwd_wrapper_dsl_sm120 so it evicts older
entries instead of retaining every SdpaBwdDslSm120 instance indefinitely.
Preserve the existing full cache key and cache-miss behavior, using a fixed size
limit via an LRU cache or equivalent bounded eviction mechanism around the
factory.
🤖 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/sdpa/bwd/api_dsl.py`:
- Around line 379-431: Bound the specialization cache used by
sdpa_bwd_wrapper_dsl_sm120 so it evicts older entries instead of retaining every
SdpaBwdDslSm120 instance indefinitely. Preserve the existing full cache key and
cache-miss behavior, using a fixed size limit via an LRU cache or equivalent
bounded eviction mechanism around the factory.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 024057ac-9482-4559-a92a-fe5fadfafd3d

📥 Commits

Reviewing files that changed from the base of the PR and between b7ddaae and 48785e4.

📒 Files selected for processing (16)
  • python/cudnn/engines/engine_ids.py
  • python/cudnn/engines/manifest.py
  • python/cudnn/frost/tile_dsl/mma.py
  • python/cudnn/frost/tile_dsl/swizzle.py
  • python/cudnn/sdpa/bwd/__init__.py
  • python/cudnn/sdpa/bwd/api_dsl.py
  • python/cudnn/sdpa/bwd/config_sm120.py
  • python/cudnn/sdpa/bwd/engine.py
  • python/cudnn/sdpa/bwd/engines.py
  • python/cudnn/sdpa/bwd/kernels/__init__.py
  • python/cudnn/sdpa/bwd/kernels/bprop_f16_sm120.py
  • python/cudnn/sdpa/fwd/engines.py
  • python/cudnn/sdpa/fwd/kernels/prefill_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
🚧 Files skipped from review as they are similar to previous changes (11)
  • python/cudnn/sdpa/bwd/kernels/init.py
  • python/cudnn/sdpa/bwd/init.py
  • python/cudnn/frost/tile_dsl/swizzle.py
  • python/cudnn/engines/manifest.py
  • python/cudnn/sdpa/fwd/kernels/prefill_f16_sm120.py
  • python/cudnn/frost/tile_dsl/mma.py
  • python/cudnn/sdpa/bwd/engine.py
  • python/cudnn/engines/engine_ids.py
  • python/cudnn/sdpa/fwd/engines.py
  • test/python/sdpa/frost/test_sdpa_bwd_dsl_sm120.py
  • python/cudnn/sdpa/graph_analyzer.py

Comment thread python/cudnn/frost/tile_dsl/swizzle.py Outdated
@Aneureka
Aneureka requested a review from vedaanta August 5, 2026 09:10
Comment thread test/python/sdpa/frost/test_sdpa_fwd_dsl_sm120.py
@Aneureka

Aneureka commented Aug 5, 2026

Copy link
Copy Markdown
Member

Nice job! LGTM overall; @vedaanta may want to take a look as well.

The next steps are to make the kernel perf-ready and add more features. By the way, you may run test_mhas_v2.py to see the coverage of the FROST sdpa_fwd kernel.

@vedaanta vedaanta left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM! 🚀

@vedaanta

vedaanta commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

@cudnn-ci-bot run

@cudnn-ci-bot

Copy link
Copy Markdown

cuDNN CI bot run targets

@cudnn-ci-bot run <targets> mirrors the PR head SHA and launches a pipeline. The analysis and build stages and the sanitizer tests run on every pipeline; every other stage waits on a gate job in the pipeline's manual stage. Naming a target opens its gate, and anything unnamed stays closed and can be started from the pipeline page.

Target Gate Starts
backend manual:backend backend:dev, backend:rel (downstream cudnn/cudnn pipelines)
frost manual:frost frost_tests:sdpa, :linear_attention, :gemm, :sm120
multi_gpu manual:multi_gpu multi_gpu_smoke:lyris
oss manual:oss oss:rel, oss:rubin
pycudnn manual:pycudnn pycudnn:dev, pycudnn:rel
python_samples manual:python_samples py_samples:ga, py_samples:rel
python_tests manual:python_tests py_test:dev, py_test:rel

Targets are comma-separated: @cudnn-ci-bot run python_samples,oss. @cudnn-ci-bot run on its own posts this list.

Aliases: frost_tests -> frost, multi-gpu -> multi_gpu, multigpu -> multi_gpu, python-samples -> python_samples, python-tests -> python_tests, samples -> python_samples.

Only allowlisted maintainers can use @cudnn-ci-bot run.

@Aneureka

Aneureka commented Aug 6, 2026

Copy link
Copy Markdown
Member

@cudnn-ci-bot run frost

@cudnn-ci-bot

Copy link
Copy Markdown

🚀 Running mirror pipeline

Branch: cudnn-gh/pr-486-3ab04dc
Pipeline: 61324024
Targets: frost

@Adnios

Adnios commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator Author

@cudnn-ci-bot run frost

@cudnn-ci-bot

Copy link
Copy Markdown

Pipeline not launched

Reason: @Adnios is not allowlisted to run this bot.

Ask an allowlisted maintainer to comment @cudnn-ci-bot run.

@Aneureka

Aneureka commented Aug 6, 2026

Copy link
Copy Markdown
Member

@cudnn-ci-bot run frost

@cudnn-ci-bot

Copy link
Copy Markdown

🚀 Running mirror pipeline

Branch: cudnn-gh/pr-486-0f3bf39
Pipeline: 61350699
Targets: frost

@Aneureka
Aneureka merged commit f843ff8 into NVIDIA:develop Aug 6, 2026
1 check passed
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.

4 participants