Skip to content

frost(spda): support ragged stats for SM120 frost sdpa forward engine - #508

Merged
vedaanta merged 4 commits into
NVIDIA:developfrom
Aneureka:haobing/frost/sm120_sdpa_thd_stats
Aug 7, 2026
Merged

frost(spda): support ragged stats for SM120 frost sdpa forward engine#508
vedaanta merged 4 commits into
NVIDIA:developfrom
Aneureka:haobing/frost/sm120_sdpa_thd_stats

Conversation

@Aneureka

@Aneureka Aneureka commented Aug 7, 2026

Copy link
Copy Markdown
Member

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

Summary

Enable thd_stats=True for the SM120 FROST SDPA forward engine. The ragged stats output is written directly in the layout the graph declares — both packed layouts in use are supported:

declared layout strides (dims (B, H, S, 1)) ragged offsets kernel store
token-major [t, h] stride_h == 1, stride_s == H cu_q * H lse[cu_q[b] + row, head]
head-major [h, t] stride_s == 1, stride_h == head_stride cu_q lse[head, cu_q[b] + row]

Why

To enhance the SM120 FROST SDPA forward engine.

Related issues

Related to #381.

API and compatibility impact

SdpaFwdDslSm120 now accepts THD graphs with a stats output (both declared layouts); previously rejected with NotImplementedError. Dense stats behavior unchanged.

Testing

  • Test command: pytest sdpa/frost/test_sdpa_fwd_dsl_sm120.py -m "L0 or L1"
  • Test result: 52 passed, 0 failed

Summary by CodeRabbit

  • New Features

    • Added ragged THD attention statistics (LSE) output with token-major and head-major layouts.
    • Added statistics support for causal attention, sliding windows, grouped-query attention, sinks, zero-length inputs, and mixed head dimensions.
    • Expanded support for eligible ragged SDPA graph configurations.
  • Bug Fixes

    • Added validation for statistics buffer shapes, strides, layouts, and presence.
    • Improved zero-key/value handling with zero outputs and appropriate statistics values.
    • Reduced workspace requirements when statistics output is enabled.

@Aneureka Aneureka self-assigned this Aug 7, 2026
@Aneureka Aneureka 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 7, 2026
@Aneureka

Aneureka commented Aug 7, 2026

Copy link
Copy Markdown
Member Author

@cudnn-ci-bot run frost

@cudnn-ci-bot

Copy link
Copy Markdown

🚀 Running mirror pipeline

Branch: cudnn-gh/pr-508-b21391f
Pipeline: 61582156
Targets: frost

@coderabbitai

coderabbitai Bot commented Aug 7, 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: c4cad94a-f894-487f-a0ee-13365442d70b

📥 Commits

Reviewing files that changed from the base of the PR and between 510a425 and 05f1e2b.

📒 Files selected for processing (1)
  • python/cudnn/sdpa/fwd/engines.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • python/cudnn/sdpa/fwd/engines.py

📝 Walkthrough

Walkthrough

SM120 THD execution now supports caller-provided ragged LSE output in token-major and head-major layouts. Runtime validation, kernel specialization, zero-KV handling, workspace behavior, and test coverage were updated.

Changes

SM120 THD LSE support

Layer / File(s) Summary
THD LSE validation and dispatch
python/cudnn/sdpa/fwd/api_dsl.py, python/cudnn/sdpa/fwd/engines.py
SM120 validates ragged LSE layouts, passes caller buffers to the kernel, supports zero-KV outputs, and enables THD statistics.
Kernel LSE layout specialization
python/cudnn/sdpa/fwd/kernels/prefill_f16_sm120.py
The kernel supports token-major (T, H) and head-major (H, head_stride) LSE storage with layout-specific specialization and stride validation.
Ragged LSE validation coverage
test/python/sdpa/frost/test_sdpa_fwd_dsl_sm120.py, test/python/sdpa/frost/test_sdpa_graph_analyzer.py
Tests cover layouts, masks, sinks, zero-length and zero-KV inputs, mixed head dimensions, contract errors, and graph eligibility.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant SM120Execute
  participant THDHelper
  participant SM120Kernel
  participant LSEBuffer
  SM120Execute->>THDHelper: pass optional LSE tensor
  THDHelper->>LSEBuffer: construct token-major or head-major view
  THDHelper->>SM120Kernel: compile and dispatch with LSE layout
  SM120Kernel->>LSEBuffer: write ragged LSE values
Loading

Possibly related PRs

Suggested reviewers: vedaanta

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies support for ragged statistics in the SM120 FROST SDPA forward engine.
Description check ✅ Passed The description covers the required sections, explains the change and compatibility impact, and reports an exact test command with results.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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: 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_fwd_dsl_sm120.py`:
- Line 465: In the loop over seq_q_lens and seq_kv_lens, rename the unused
unpacked variable nkv to _nkv so Ruff B007 recognizes it as intentionally
unused.
🪄 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: c5e5fd89-b614-41d4-be1c-2a9ba0b88bca

📥 Commits

Reviewing files that changed from the base of the PR and between ec13987 and b21391f.

📒 Files selected for processing (5)
  • python/cudnn/sdpa/fwd/api_dsl.py
  • python/cudnn/sdpa/fwd/engines.py
  • python/cudnn/sdpa/fwd/kernels/prefill_f16_sm120.py
  • test/python/sdpa/frost/test_sdpa_fwd_dsl_sm120.py
  • test/python/sdpa/frost/test_sdpa_graph_analyzer.py

Comment thread test/python/sdpa/frost/test_sdpa_fwd_dsl_sm120.py Outdated
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@Aneureka

Aneureka commented Aug 7, 2026

Copy link
Copy Markdown
Member Author

@cudnn-ci-bot run frost

@cudnn-ci-bot

Copy link
Copy Markdown

🚀 Running mirror pipeline

Branch: cudnn-gh/pr-508-05f1e2b
Pipeline: 61603100
Targets: frost

@vedaanta
vedaanta merged commit 3f17f5b into NVIDIA:develop Aug 7, 2026
1 check passed
vedaanta added a commit to vedaanta/cudnn-frontend that referenced this pull request Aug 7, 2026
With both the SM120 engine (NVIDIA#508) and the SM100 f16 flavors serving
ragged Stats, every row with thd=True also had thd_stats=True, so the
dedicated gate could never fire: THD + generate_stats eligibility now
follows from thd AND stats alone (the FP8/MXFP8 rows keep thd=False).
A future partial bring-up that lands THD before its stats plumbing
re-adds the axis with its precise decline message.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
vedaanta added a commit that referenced this pull request Aug 8, 2026
…#512)

* frost(sdpa): support ragged stats for SM100 frost sdpa forward engine

Port of the SM120 ragged-Stats support (#508) to the SM100 f16/bf16
flavors (d128, d192/d128, d256, d512). The SM100 THD kernels always
write a packed LSE; it previously landed in workspace scratch in the
kernels' native head-major (1, QH, T) packing. The epilogue store is
now layout-aware and writes the caller's ragged Stats buffer directly
in the graph's declared layout — no extra kernels on the execute path:

  declared layout   | strides (dims (B, H, S, 1)) | kernel store
  ------------------|-----------------------------|---------------------------
  token-major [t,h] | stride_h == 1, stride_s == H | lse[cu_q[b] + row, head]
  head-major  [h,t] | stride_s == 1, stride_h >= T | lse[head, cu_q[b] + row]

- config_sm100: new TemplateParams.thd_lse_token_major -> CFG.THD_LSE_TOKEN_MAJOR
  (THD-only, validated); kernels gain a lse_stride compile() shape for the
  head-major padded head stride (part of the per-shape cache key); the THD
  fake LSE drops to element alignment (user buffers only guarantee 4B).
- SdpaFwdDslSm100: THD + sample_lse accepted with the same declared-layout
  validation as SM120; the packed-LSE workspace chunk is carved only for
  stats-less graphs; t_kv == 0 short-cut fills the Stats valid region with
  -inf (or the sink logit alone) in either layout; strict lse_tensor
  presence contract in both directions for THD.
- engines: the SM100 f16 spec advertises thd_stats.

Testing (cc 10.0):
  pytest test_sdpa_fwd_dsl_sm100.py -m "L0 or L1"  (thd/graph_api slice:
    102 passed; new stats/contract tests: 15 passed)
  pytest test_sdpa_graph_analyzer.py               (69 passed)
  pytest test_sdpa_fwd_{fp8,mxfp8}_sm100.py        (46 passed)

Related to #381.

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

* frost(sdpa): has_lse specialization + per-shape stats layout for SM100

Review follow-ups on the SM100 ragged-stats port, bringing the f16
kernels to full SM120 parity on the LSE contract:

- has_lse specialization: the f16 kernels (d128, d192/d128, d256, d512)
  now None-specialize the LSE argument — a stats-less graph compiles the
  LSE store out. All dummy-LSE scratch disappears: dense inference
  graphs report get_workspace_size() == 0 (was b*h*s*4), THD keeps only
  its metadata chunks, and the SM100 f16 spec advertises lse_optional.
  The lse_tensor execute contract is strict in both directions (an
  unrequested dense lse_tensor is now rejected instead of silently
  written). FP8/MXFP8 kernels still write an LSE unconditionally and
  keep the engine-carved dummy.

- No template parameter for the THD stats layout (mirrors SM120's
  per-compile keying): TemplateParams.thd_lse_token_major and
  CFG.THD_LSE_TOKEN_MAJOR are gone. The layout is a per-shape compile()
  specialization encoded in the LSE fake tensor's static layout —
  token-major binds its natural packed rank-2 (T, H) view, head-major
  keeps the native rank-3 (1, QH, head_stride) packing, and the epilogue
  branches on the static rank.

- THD metadata built host-side (SM100 AND SM120 adapters): the two
  device-side torch.cumsum calls each allocated scan-temp storage and
  launched a kernel per execute. The [seq_kv | cu_q | cu_k] buffer is
  now built on the host from the (inherent) tolist round-trip and
  uploaded in one H2D copy; the slq/slk workspace copies go away too.
  test_workspace_carve_no_per_execute_allocs_and_guards is reworked to a
  THD graph (dense no longer needs a workspace) and asserts zero
  per-execute CUDA allocations.

Testing (cc 10.0): sm100 suite -m "L0 or L1" -k "thd or graph_api or
stats or contract" 111 passed; frontend integration 10 passed;
fp8+mxfp8+analyzer 115 passed. The SM120 suite skips locally (no SM120
GPU); its metadata change is mechanically identical and CI-covered.

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

* frost(sdpa): drop the vestigial thd_stats capability axis

With both the SM120 engine (#508) and the SM100 f16 flavors serving
ragged Stats, every row with thd=True also had thd_stats=True, so the
dedicated gate could never fire: THD + generate_stats eligibility now
follows from thd AND stats alone (the FP8/MXFP8 rows keep thd=False).
A future partial bring-up that lands THD before its stats plumbing
re-adds the axis with its precise decline message.

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

* frost(sdpa): route the all-KV-zero THD case through the kernel dead-row path

Review follow-up (AGENTS.md Rule 1 — execute is a zero-surprise hot
path): the t_kv == 0 short-cut re-implemented the kernels' dead-row
semantics adapter-side with zero_/fill_/copy_ writes — surprise kernel
launches and a second copy of the same semantics that can drift.

Both kernels already serve dead rows (row_sum <= 0 -> O := 0 and
LSE := -inf, or the sink alone), pinned by the live-launch zero-KV
sequence tests. The only launch blocker was the zero-token packed K/V
view (a CuTe layout mode must be > 0), so the adapters now clamp the
packed KV extent to ONE never-dereferenced token — every sequence's KV
tile range is empty, so no K/V load is ever issued — bound over storage
the contract already guarantees: Q backs K (kh*d_qk <= t_q*qh*d_qk), O
backs V (kh*d_v <= t_q*qh*d_v). Views only; the short-cut, the
adapter-side fills, and the O zero-fill are gone from both the SM100
and SM120 adapters, and AGENTS.md Rule 1 gains a bullet making the
no-degenerate-path-fixups expectation explicit.

Testing (cc 10.0): all_kv_zero + zero_length tests 5 passed (now
exercising the kernel path); sm100 suite -k "thd or graph_api or stats
or contract" 111 passed; integration + analyzer 79 passed. The SM120
suite skips locally (no SM120 GPU); its change is the same mechanical
transformation, CI-covered.

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

* frost(sdpa) tests: pin t_q == 0 as a complete no-op (all-zero seq_len_q)

The adapters early-return when no query token exists anywhere (t_q ==
0: the packed O/Stats have zero rows, nothing to compute or write), but
no test pinned it — the zero-length coverage always kept live Q tokens.
The random backend sweeps can generate the case (a B=1 batch draws a
zero seq_len_q with 10% probability), so frameworks do hit it.

The THD harnesses now pre-fill the O and ragged Stats storages with a
sentinel (2048.0, exact in fp16/bf16/fp32): live tests still compare
the kernel-written packed region against the reference, and the new
test_dsl_sm1xx_thd_all_q_zero_stats (both stats layouts, live KV and
all-zero KV) asserts the buffers come back untouched end to end
through the graph -> engine -> adapter stack. The SM100 harness gains
the same declared-extent clamp for all-zero seq_len_q that it already
had for seq_len_kv (SM120's harness had both).

Testing (cc 10.0): new all_q_zero tests + sentinel-affected neighbors
11 passed; full sm100 THD/stats slice 100 passed. SM120 mirror is
CI-covered (no SM120 GPU locally).

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

* docs: tighten the AGENTS.md degenerate-path bullet

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

* frost(sdpa): put the compile() noqa on the def line (review)

CodeRabbit: the A001 (builtin shadowing) suppression must sit on the
`def compile(` line; the three kernels that had it on the closing-paren
line were suppressing nothing.

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

* frost(sdpa): standardize on thd_stats_head_major / lse_head_major (review)

Haobin: SM100 stored thd_stats_token_major (False = its kernel's native
head-major packing) while SM120 stores thd_stats_head_major (False =
token-major) — each flag named after its kernel's NON-native layout.
Standardize both adapters and every kernel compile() on the SM120 /
contract-aligned vocabulary: thd_stats_head_major == False means
token-major, matching cuDNN's TH1 ragged Stats recipe, and the SM100
kernels' compile() keywords become lse_head_major / lse_head_stride —
identical signatures across all five kernels. Naming/polarity only;
the layout is always derived explicitly from the graph's declared
strides on every live path, so no behavior changes. Also fixes the
stale [slq32 | slk32] workspace comment in the carve test.

Testing (cc 10.0): sm100 stats/contract slice 17 passed.

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