Skip to content

frost(sdpa_bwd_sm80): serve THD ports at their own head stride - #1108

Draft
egilliam-nv wants to merge 1 commit into
NVIDIA:developfrom
egilliam-nv:sm80-thd-head-strides
Draft

egilliam-nv wants to merge 1 commit into
NVIDIA:developfrom
egilliam-nv:sm80-thd-head-strides

Conversation

@egilliam-nv

@egilliam-nv egilliam-nv commented Sep 16, 2026

Copy link
Copy Markdown
Collaborator

Summary

sdpa_bwd_sm80 now serves packed THD ports at their own head stride, not only their own token stride. Independent of draft PR #1058 (which will rebase onto this once it lands).

Why

PR #960 turned on head-axis stride gaps in the ragged sweeps: each ragged Q/K/V/O independently becomes a head-interleaved record (head stride D + k·16 bytes). The SM80 THD backward addressed a row as token × token_stride + head × D and declined any other head stride, so with CUDNN_FRONTEND_ENABLE_FROST_ENGINES=1 on A100 the backward ragged sweep went from 383 draws served by this row to 48. The cuDNN backend declines every ragged backward on SM80, so the other draws ran nowhere.

test_sdpa_random_bwd_ragged_L0, A100, FROST on served by sdpa_bwd_sm80
before #960 383 of 384
develop today (#960 in) 48 of 384
this PR 291 of 291 eligible (the other 93 draw stats_use_log2, which the SM80 forward does not yet declare; those skip before the backward)

What changed

  • Kernels: the head stride rides the compiled fake like the token stride; every site that multiplied head by D reads X.stride[2] instead (Q/dO and K/V tile bases, direct-bound dK/dV stores, O·dO dot, bounded dQ cast, dK/dV fold). A compact port keeps the compact fake, byte-identical codegen.
  • compile(): thd_head_strides (eight ports, 0 = D), validated with the token strides; _fake_rows(..., ts, hs).
  • Rule (engine mismatch and adapter check_support): element stride 1, head stride >= D, token stride >= H × head_stride, each a multiple of 8 elements (every head base 16-byte aligned for the cp.async loads). Size-1 head axis wildcards as before. The execute-time view check pins the plan's head stride too.

Tests

test_sdpa_bwd_thd_sm80.py: test_graph_thd_gapped_head_strides ×5 (every port head-gapped, head and token gaps together, GQA, padded head dim, causal + deterministic) with NaN gap cells asserted never read or written; test_accept_thd_gapped_head_strides, test_reject_thd_misaligned_head_stride, test_reject_thd_head_stride_below_the_head.

Local (A100): SM80 THD / analyzer / integration / stream-respect / api-index suites 198 passed; ragged backward sweep with FROST on 291 passed, 93 skipped (log2 draws), 0 failed.

Docs

Tracker footnote ᵏ, _sm80_spec docstring, kernel and adapter comments.

Labels

cat-enhancements · area:frost · area:global_attention · orig-nv-eng

🤖 Generated with Claude Code

@egilliam-nv egilliam-nv added this to the Frontend 1.30.0 milestone Sep 16, 2026
@coderabbitai

coderabbitai Bot commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

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

@egilliam-nv

egilliam-nv commented Sep 16, 2026

Copy link
Copy Markdown
Collaborator Author

Independent of PR #1058 (restacked directly onto develop). Motivated by PR #960's head-gap fuzzing, which left the SM80 THD backward serving 48 of 384 ragged sweep draws on A100 with FROST engines enabled.

The SM80 backward's packed THD path addressed a row as
token * token_stride + head * D: the token stride was plan-time per port
(the compiled fake carried it) but the head stride was fixed at D, and the
engine rule and the adapter declined anything else.  PR NVIDIA#960 turned on
head-axis stride gaps in the ragged sweeps (each ragged port a
head-interleaved record, head stride D + k*16 bytes), so with FROST engines
enabled test_sdpa_random_bwd_ragged_L0 on A100 fell from 383 draws served
by this row to 48 -- the rest ran nowhere, the cuDNN backend declining every
ragged backward on SM80.

The head stride now rides the fake like the token stride: compile() takes
thd_head_strides (eight ports, 0 = D) and _fake_rows builds
(T*ts, ts, hs, 1); the kernels read X.stride[2] where they multiplied by D
-- the Q/dO and K/V tile bases, the direct-bound dK/dV stores, the O.dO
dot, the bounded dQ cast and the dK/dV fold.  A compact port keeps the
compact fake (byte-identical codegen); a staged port (head dim inside the
flavor envelope) stays compact at the kernel.

Rule (engine mismatch and adapter check_support): element stride 1, head
stride >= D, token stride >= H * head_stride, each a multiple of 8 elements
so every head base stays 16-byte aligned for the cp.async loads; the head
stride wildcards on a size-1 head axis as before.  The execute-time view
check pins the plan's head stride alongside its token stride.

Tests: five head-gapped graph cases (every port, head and token gaps
together, GQA, a padded head dim, causal + deterministic) with NaN-filled
gap cells asserted never read or written -- the gap-cell helper now covers
head gaps as well as token gaps -- plus accept / misaligned / overlapping
probe cases.  Tracker footnote k and the engine docstring updated.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@egilliam-nv egilliam-nv self-assigned this Sep 16, 2026
@egilliam-nv

Copy link
Copy Markdown
Collaborator Author

@cudnn-ci-bot run python_tests,frost

@cudnn-ci-bot

cudnn-ci-bot commented Sep 16, 2026

Copy link
Copy Markdown

🏁 Pipeline finished

SHA: d1790fc
Targets: python_tests, frost
Branch: cudnn-gh/pr-1108-d1790fc
Pipeline: 68241732
Last updated: 2026-09-17 00:36 UTC

31 passed, 2 failed, 5 manual

manual

  • manual:python_samples - Manual
  • manual:python_tests - ✅ Passed
  • manual:frost - ✅ Passed
  • manual:oss - Manual
  • manual:pycudnn - Manual
  • manual:multi_gpu - Manual
  • manual:backend - Manual

analysis

  • analysis:cudnn_clang_disable_exception - ✅ Passed
  • analysis:cudnn_v9_no_half_conversion - ✅ Passed
  • analysis:cudnn_clang - ✅ Passed
  • analysis:check-relative-includes - ✅ Passed
  • analysis:check-CUDNN_FRONTEND_SKIP_JSON_LIB - ✅ Passed
  • analysis:guardwords_scan - ❌ Old Failure (nightly failed)
  • analysis:jax-import-guard - ✅ Passed
  • san:build - ✅ Passed

build

  • analysis:api_index - ✅ Passed
  • build:dev:linux:amd64 - ✅ Passed
  • build:rel:linux:amd64 - ✅ Passed
  • build:dev:linux:arm64 - ✅ Passed
  • build:rel:linux:arm64 - ✅ Passed
  • build:rel:win:amd64 - ✅ Passed

frost_tests

  • frost-sdpa:cutlass-rel:sm80 - ✅ Passed
  • frost-sdpa:cutlass-rel:sm100 - ✅ Passed
  • frost-sdpa:cutlass-rel:sm120 - ✅ Passed
  • frost-linear:cutlass-rel:sm100 - ✅ Passed
  • frost-gemm:cutlass-rel:sm100 - ✅ Passed
  • frost-sdpa:cutlass-rel:sm103 - ✅ Passed
  • frost-sdpa:cutlass-4.8:sm107 - ❌ Old Failure (nightly failed)

python_tests

  • py_test:dev:sm80 - ✅ Passed
  • py_test:dev:sm90 - ✅ Passed
  • py_test:dev:sm100 - ✅ Passed
  • py_test:rel:sm80 - ✅ Passed
  • py_test:rel:sm90 - ✅ Passed
  • py_test:rel:sm100 - ✅ Passed

sanitizer_tests

  • san:cpp_test:sm80 - ✅ Passed
  • san:cpp_test:sm90 - ✅ Passed
  • san:cpp_test:sm100 - ✅ Passed

triage

  • triage:ai - ✅ Passed

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants