Skip to content

Reduce prepared SDPA execution overhead - #1151

Open
YangXu1990uiuc wants to merge 13 commits into
NVIDIA:developfrom
YangXu1990uiuc:yanxu/sdpa-prepared-execute-overhead
Open

YangXu1990uiuc wants to merge 13 commits into
NVIDIA:developfrom
YangXu1990uiuc:yanxu/sdpa-prepared-execute-overhead

Conversation

@YangXu1990uiuc

@YangXu1990uiuc YangXu1990uiuc commented Sep 20, 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 reviewed the Hard Rules in the AGENTS.md for each directory this PR touches and my changes comply.
  • I added GitHub labels: one cat-*, one or more area:* / op:*, and one orig-*.

Affected area

Python API or bindings; FE OSS kernels or CuTeDSL.

Summary

Reduce the host work in an already built FROST SDPA plan, including small-query split-KV execution. Previously split decode stayed on the tensor adapter and rebuilt buffer facts and workspace views on every call. The prepared path now binds the caller's partial workspace and final outputs directly, then launches attention and combine on the same stream.

  • Migrate SM100 D128 and D256 f16/bf16 decode to the existing explicit pointer ABI. Delete the obsolete f16 tensor host, shape/stride-specialized fake-tensor compile branches, and adapter compile/execute fallback. Keep each kernel's host and pipeline explicit.

  • Specialize D256 contiguous page-table columns and common O/Stats inner strides in the compiled host, with per-call branches retaining the general Int64 stride path. The device pipeline and public ABI remain unchanged.

  • Prepare split-KV launches with independent per-call frames. Partial O uses the kernel's required dtype; partial LSE stays natural-log even without user Stats. The combine writes the actual final O/LSE strides, including padded layouts, without an O scratch/copy-back.

  • Preserve Int64 stride leaves through annotations and compile placeholders, including all seven sibling prefill page-table slots. Page-table indices remain int32.

  • Cache pure THD/dense geometry and project immutable facts directly from the native variant pack. Remove the unused Python facts_of_pack and native facts() projection; tests use an independent oracle.

  • Reject mixed K/V pool layout kinds during standalone support checking. Validate output span/device/alignment/overlap and compiled shapes before launching; metadata inputs also check the producer storage span after shape overrides.

  • Make FE-owned resource destruction safe during unrelated CUDA Graph capture: restore the thread capture mode after cleanup, avoid retaining backend exception tracebacks, and use existing aligned buffers for unused prepared ABI slots. Zero-KV THD descriptor bindings require no device allocation or initialization.

No public API or attention pipeline redesign. Runtime buffers, workspace and streams are rebound per call; no execute-time JIT or tensor views/copies in the prepared graph path. Split plans retain their declared (B, S_q) workspace envelope. Quantized callers retain their used tensor ABI and existing scaling/amax semantics. Capability rows and heuristic selection are unchanged.

Follows #1119 and #1132; completes the page-table stride coverage left outside #1146.

Validation

Current revision: a2814ba54.

  • 253 focused correctness tests pass (3 architecture skips, 1 deselected), covering capture/GC lifetime, dispatch, variant packs, native lowering, prepared dense/THD/split execution, D128/D256 decode and the pointer ABI. Four final explicit-stream lifetime cases also pass.
  • 29 focused tests pass with the CuTe DSL 4.7.0 minimum. No dependency-floor increase or global GC suppression is needed by the implementation.
  • Six controlled lifetime regressions fail on the previous source/native pair and pass after the fix. Forced GC and capture-mode restoration are tested independently from timing.
  • Nonunit page-table/output strides, metadata span/alignment, workspace rebinding, separate call frames and quantized combine callers remain covered. The forced contiguous-only negative control fails all four nonunit page-table cases numerically.
  • Production B200 validation at the current revision passes all 56 records: seven geometries, O/Stats, four ABBA arms. Every record checks full O/LSE against a CPU FP32 reference, actual FROST routing, poisoned-output replay and changed-V replay.
  • Changed-file formatting/license checks pass. Other architecture lanes remain for CI; local and B200 results do not establish their execution.

Performance

NVIDIA B200, BF16, cuDNN 9.26 GA. Current a2814ba54 versus preceding f41892792, ABBA order. Each value is the mean of two process medians. Both arms load the native extension corresponding to their revision; this compares the complete revisions.

Case Host enqueue, preceding → current Captured GPU, preceding → current
Dense D256 / split1 / Stats 25.285 → 25.817 µs 16.148 → 15.335 µs
Dense D256 / split2 / O 38.677 → 39.627 µs 13.642 → 12.824 µs
NHD D256 / split2 / O 45.019 → 45.361 µs 14.618 → 13.701 µs
NHD D256 / split2 / Stats 48.029 → 48.616 µs 15.435 → 14.718 µs

These small cases use B2/Hq8/Hkv2/Q4/KV1024; paged cases use page16 and noncontiguous block IDs. The matrix also includes D128/D256 B64 controls and a long-KV paged D256 control. Small D256 Stats/split GPU time improves 3.48–6.28%; dense split1 O is essentially unchanged. Mean host enqueue increases by 0.005–1.213 µs across the measured settings, with mixed directions in some repeated pairs.

The larger host reductions from the tensor-to-prepared migration were measured earlier (50c2e5494f41892792): for example, paged D128 split2 131.22 → 48.57 µs and paged D256 split2 90.80 → 48.30 µs, both B1/Hkv1/Q1/KV32768/page16 without Stats. That earlier matched-source ABBA passed 72/72 settings and held the compatible native extension fixed. Those numbers belong to the earlier heads, not the current revision.

A same-input comparison with a separate earlier 50c2e5494 batch still leaves up to 4.37% GPU overhead for the current small dense D256 case; it is cross-batch context, not a direct final-versus-50c2 ABBA. The current change recovers much of the small D256 GPU loss while retaining the prepared host path; it does not establish a uniform GPU improvement over the original tensor path.

Host timing measures idle single-call public FE graph.execute() enqueue, with synchronization outside the timer. GPU timing measures warm captured replay on one ordered non-default stream. Compilation, reference computation and capture are excluded. These are component results, not FlashInfer/vLLM or model throughput.

Summary by CodeRabbit

  • Performance

    • Improved reuse of compiled SDPA execution plans and layout calculations.
  • Bug Fixes

    • Improved support for dense and paged attention with varied shapes, strides, head dimensions, and large page-table strides.
    • Fixed split-KV output handling, including strided outputs, larger value dimensions, statistics, and workspace usage.
    • Improved validation for device placement, layouts, alignment, and invalid launch parameters.
    • Made CUDA graph capture and resource cleanup more reliable.
  • Testing

    • Expanded coverage for pointer-based launches, prepared plans, split-KV execution, strided outputs, and capture lifetime behavior.

@YangXu1990uiuc YangXu1990uiuc added orig-nv-eng Reported or requested by NVIDIA engineering. cat-perf-bug Performance regressions or cases where behavior is correct but too slow. area:frost area:global_attention labels Sep 20, 2026
@coderabbitai

coderabbitai Bot commented Sep 20, 2026

Copy link
Copy Markdown
Contributor

Review Change StackReview 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: Repository: NVIDIA/cudnn-frontend/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 331683d5-42b7-4ab7-ba5f-fc010a75bf11

📥 Commits

Reviewing files that changed from the base of the PR and between f418927 and a2814ba.

📒 Files selected for processing (11)
  • include/cudnn_frontend_shim.h
  • python/cudnn/AGENTS.md
  • python/cudnn/_pygraph.py
  • python/cudnn/frost/buffers.py
  • python/cudnn/sdpa/fwd/kernels/sm100/decode_d256_f16.py
  • python/cudnn/sdpa/fwd/prepared.py
  • python/pygraph/pygraph.h
  • test/python/sdpa/frost/test_sdpa_prepared_geometry.py
  • test/python/sdpa/frost/test_sdpa_prepared_thd.py
  • test/python/test_cuda_capture_lifetime.py
  • test/python/test_dispatch.py
💤 Files with no reviewable changes (1)
  • test/python/sdpa/frost/test_sdpa_prepared_geometry.py

Included review availability: Your plan provides up to 12 included reviews per hour; 11 remain after this review.


📝 Walkthrough

Walkthrough

The changes route dense SDPA through prepared launches, add runtime-bound pointer ABIs for SM100 decode kernels, project native operand facts, preserve 64-bit strides, support strided split-combine outputs, and harden CUDA resource cleanup and backend error handling.

Changes

Prepared SDPA execution

Layer / File(s) Summary
Native facts and geometry caching
python/pygraph/variant_pack.cpp, python/cudnn/sdpa/fwd/config_sm100.py, python/cudnn/sdpa/fwd/prepared.py, test/python/sdpa/frost/test_sdpa_native_facts.py, test/python/sdpa/frost/test_sdpa_prepared_geometry.py
Native code exposes typed facts and effective strides. Dense stride results use bounded caching. Per-call validation remains active.
Prepared dense and split-KV execution
python/cudnn/sdpa/fwd/api_dsl.py, python/cudnn/sdpa/fwd/prepared.py, python/cudnn/sdpa/fwd/engine.py, python/cudnn/sdpa/fwd/engines.py, test/python/sdpa/frost/test_sdpa_prepared_thd.py
Dense execution uses prepared specifications. Split-KV binds caller workspace and outputs, validates metadata, and runs the main kernel followed by the combine kernel.
Runtime-bound pointer ABI
python/cudnn/sdpa/fwd/kernels/sm100/decode_d128_f16.py, python/cudnn/sdpa/fwd/kernels/sm100/decode_d256_f16.py, python/cudnn/sdpa/fwd/kernels/sm100/prefill_*, python/cudnn/sdpa/fwd/kernels/sm107/prefill_*, test/python/sdpa/frost/test_sdpa_fwd_pointer_abi.py, test/python/sdpa/frost/test_sdpa_fwd_decode_d128_sm100.py, test/python/sdpa/frost/test_sdpa_fwd_decode_d256_sm100.py
Decode hosts bind pointers, Int64 strides, metadata, and paged-KV options at launch. Compilation specializes supported dimensions, LSE options, and paged layout.
Strided split-combine outputs
python/cudnn/sdpa/fwd/kernels/sm100/split_combine.py, test/python/sdpa/frost/test_sdpa_split_combine_sm100.py
The combine path supports wider value dimensions, pointer compilation, caller-provided output strides, full multidimensional stores, optional LSE, and quantized output handling.
Capture-safe cleanup and detached errors
include/cudnn_frontend_shim.h, python/cudnn/frost/buffers.py, python/pygraph/pygraph.h, python/cudnn/_pygraph.py, test/python/test_cuda_capture_lifetime.py, test/python/test_dispatch.py
Resource cleanup preserves CUDA stream-capture mode. Backend decline exceptions no longer retain traceback frames or graph references.

Priority: ⬇️ Low

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

Change: Refactor

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant FrostSdpaFwdPlan
  participant PreparedBinder
  participant SDPAKernel
  participant SplitCombine
  Caller->>FrostSdpaFwdPlan: execute runtime tensors and metadata
  FrostSdpaFwdPlan->>PreparedBinder: bind validated facts, workspace, and outputs
  PreparedBinder->>SDPAKernel: launch prepared dense or decode kernel
  SDPAKernel->>SplitCombine: provide split partials when split-KV is enabled
  SplitCombine-->>Caller: write final output and optional LSE
Loading

Possibly related PRs

Suggested reviewers: vedaanta, anerudhan

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.31% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 161 functions across 30 files. (1 skipped… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
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.
Title check ✅ Passed The title clearly summarizes the primary change: reducing execution overhead for prepared SDPA plans.
Description check ✅ Passed The description is detailed and covers the affected areas, changes, rationale, compatibility impact, related issues, testing, and performance. It uses “Validation” instead of the template’s “Testing” …
Full details: Docstring Coverage

Explanation

Docstring coverage is 50.31% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 161 functions across 30 files. (1 skipped: 1 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR

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

@YangXu1990uiuc

Copy link
Copy Markdown
Collaborator Author

@cudnn-ci-bot run frost python_tests

@cudnn-ci-bot

cudnn-ci-bot commented Sep 20, 2026

Copy link
Copy Markdown

🏁 Pipeline finished

SHA: 013f4ed
Targets: frost, python_tests
Branch: cudnn-gh/pr-1151-013f4ed
Pipeline: 68828033
Last updated: 2026-09-20 02:07 UTC

26 passed, 7 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 - ✅ Passed
  • 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 - ❌ Old Failure (nightly failed)
  • py_test:dev:sm90 - ❌ Old Failure (nightly failed)
  • py_test:dev:sm100 - ❌ Old Failure (nightly failed)
  • py_test:rel:sm80 - ❌ Old Failure (nightly failed)
  • py_test:rel:sm90 - ❌ Old Failure (nightly failed)
  • py_test:rel:sm100 - ❌ Old Failure (nightly failed)

sanitizer_tests

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

triage

  • triage:ai - ✅ Passed

@YangXu1990uiuc

Copy link
Copy Markdown
Collaborator Author

@cudnn-ci-bot run frost python_tests

@cudnn-ci-bot

cudnn-ci-bot commented Sep 20, 2026

Copy link
Copy Markdown

🏁 Pipeline finished

SHA: 50c2e54
Targets: frost, python_tests
Branch: cudnn-gh/pr-1151-50c2e54
Pipeline: 68830210
Last updated: 2026-09-20 02:24 UTC

26 passed, 7 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 - ✅ Passed
  • 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 - ❌ Old Failure (nightly failed)
  • py_test:dev:sm90 - ❌ Old Failure (nightly failed)
  • py_test:dev:sm100 - ❌ Old Failure (nightly failed)
  • py_test:rel:sm80 - ❌ Old Failure (nightly failed)
  • py_test:rel:sm90 - ❌ Old Failure (nightly failed)
  • py_test:rel:sm100 - ❌ Old Failure (nightly failed)

sanitizer_tests

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

triage

  • triage:ai - ✅ Passed

@YangXu1990uiuc YangXu1990uiuc left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Codex bot review · model: gpt-6-astra

Reviewed 50c2e5494512 against base 667fe4ce8ce4.

The design makes sense: one explicit decode entry, bounded caching of pure geometry, and native construction of immutable buffer facts. I found no actionable correctness or approval-blocking issue in this head. The cache hits retain per-call buffer/device/span checks and separate launch frames. Independent B200 measurements confirm the paged CPU-overhead improvement without a material GPU regression in the sampled cases. Comment-only because this PR belongs to the account running the bot.

Validation: Reviewed the complete diff and the final tensor-entry removal, traced graph/standalone/direct-kernel callers, and built the changed native binding in isolation. The final head's native sources match that binding. The exact-head SM100 targeted gate passed 253 tests, with one marker-filtered case: decode, prepared THD/dense execution, geometry caching, native facts, variant-pack normalization and dispatch. On the supported CuTe DSL 4.7 floor, 18 focused tests passed on the final head: migrated direct pointer launches, NHD/HND page sizes, forced splits with empty ranges, Int64 page-table stride, graph decode, buffer rebinding and CUDA Graph capture/replay. An additional independent probe reused one decode plan across B8/Q4/KV1024 -> B3/Q2/KV512 with padded strides -> B8/Q4/KV1024. O and a nontrivial H/B/S Stats layout matched FP64 reference math, output padding guards remained intact, and guarded compiler entry points were never called during execute. Production B200 head/base/base/head comparison against develop 667fe4c, with each arm's matching native extension, cuDNN 9.25.1, CUDA 13.2 and pinned CPU affinity. BF16, B8, Hq/Hkv=32/8, D128, KV1024, Stats enabled. All 16 case/runs passed route assertions, full FP64 O/LSE comparisons and changed-input, poisoned-output CUDA Graph replay. B200 paged Q4/page16 CPU enqueue medians (us): NHD 55.47/61.21 -> 44.21/42.17; HND 60.44/58.66 -> 40.14/42.93. GPU graph time remained about 14.36 us. Dense Q1 GPU time was 12.33 -> 12.39 us and Q4 stayed about 12.32 us. Dense CPU improvements were small or inconclusive; one Q4 head run was noisier. These are component timings, not end-to-end latency. Current-head pre-commit passed. The author already started pipeline 68830210 for 50c2e54; it is still running, so no duplicate CI was triggered.

Limitations: The independent B200 probe covers the stated B8 decode cases, not the author's B64 FlashInfer wrapper workload or a full performance sweep. A dense GPU slowdown initially seen on an engineering board did not reproduce on B200 and is not being reported as a PR defect. Full feature/wheel and architecture CI remains pending on pipeline 68830210. The focused local tests used cuDNN 9.25.1; they do not substitute for that matrix.

Comment only: GitHub does not allow reviewing one's own PR with approval/request-changes.

@YangXu1990uiuc

Copy link
Copy Markdown
Collaborator Author

CI follow-up for 50c2e549: pipeline 68830210 finished with 26 passed, 7 failed, 5 manual. The FROST SM80/SM100/SM103/SM120, GEMM and linear jobs passed.

I inspected all seven failing job summaries. The six Python jobs fail the same four cuTile linear-attention correlated-key cases. SM107 has 12 ragged-decode native backend NVRTC plan-construction failures, plus a backward worker crash; those decode stacks do not run the changed FROST decode kernel. The CI bot labels these jobs as existing nightly failures. I have not independently compared the nightly failure signatures, so this is not a clean-CI claim. No new PR-specific defect was identified in the inspected traces; my review conclusion is unchanged.

Codex bot review — model gpt-6-astra.

@YangXu1990uiuc YangXu1990uiuc added this to the Frontend 1.30.0 milestone Sep 20, 2026
@YangXu1990uiuc

Copy link
Copy Markdown
Collaborator Author

@cudnn-ci-bot run frost python_tests

@cudnn-ci-bot

cudnn-ci-bot commented Sep 20, 2026

Copy link
Copy Markdown

🏁 Pipeline finished

SHA: f418927
Targets: frost, python_tests
Branch: cudnn-gh/pr-1151-f418927
Pipeline: 68850105
Last updated: 2026-09-20 06:08 UTC

25 passed, 8 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 - ✅ Passed
  • 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 - ❌ Old Failure (nightly failed)
  • frost-sdpa:cutlass-4.8:sm107 - ❌ Old Failure (nightly failed)

python_tests

  • py_test:dev:sm80 - ❌ Old Failure (nightly failed)
  • py_test:dev:sm90 - ❌ Old Failure (nightly failed)
  • py_test:dev:sm100 - ❌ Old Failure (nightly failed)
  • py_test:rel:sm80 - ❌ Old Failure (nightly failed)
  • py_test:rel:sm90 - ❌ Old Failure (nightly failed)
  • py_test:rel:sm100 - ❌ Old Failure (nightly failed)

sanitizer_tests

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

triage

  • triage:ai - ✅ Passed

@YangXu1990uiuc YangXu1990uiuc left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Codex bot review · model: gpt-6-astra

Reviewed f4189279273d against base 667fe4ce8ce4.

The expanded prepared split path and D256 pointer ABI make sense. I found no correctness or approval blocker in the tested domain, with one nonblocking D256 unsplit GPU regression below. Split execution shows substantial host savings, and the newly prepared path honors the tested KV shape overrides. Comment-only because this is the account owner's PR.

[P2] Keep the small-grid D256 unsplit case in the performance gate (source)

The final pointer host still regresses a supported small-grid unsplit case beyond the approximately 2% range reported for the PR's matrix. On B200, BF16, B=2/Hq=8/Hkv=2/Q=4/KV=1024/D=256, BSHD Q/K/V/O, Stats enabled, and explicitly selected split_kv=1/pack_gqa=True, the dense kernel goes from 14.59 to 16.00 us (+9.7%); paged NHD with page_size=16 goes from 16.36 to 17.10 us (+4.6%). These numbers use ordinary contiguous Stats. A separate padded HBS Stats run shows the same effect. Please add this Q=4, multi-KV-head case to the matrix and investigate preserving a common-layout specialization in the pointer host, analogous to the page-table fast path. This is a localized GPU performance issue, not a numerical failure or an approval blocker; the split-path host savings remain substantial.

Evidence: Independent final f418927 versus previously reviewed 50c2e54 on one allocated B200, ABBA order, identical concrete knobs and dependencies (cuDNN 9.25.1.1, PyTorch 2.13.0, DSL 4.8). Each GPU sample averages 640 executions from captured 32-call graphs; seven samples per process and two processes per source. Every arm passes full FP64 O/LSE references and changed-input/poisoned-output replay. Dense contiguous-Stats process medians: previous 14.588/14.591 us, final 15.998/15.997 us. Paged: previous 16.351/16.359 us, final 17.103/17.103 us. Host enqueue was measured separately; this is not an end-to-end latency claim. Attribution: Introduced between the previously reviewed 50c2e54 and final f418927 by the D256 host/ABI changes. The unchanged device-function AST does not preserve its former static tensor-layout specialization. The precise generated-code cause has not been profiled.

Validation: Latest f418927: 49 D256/pointer-ABI tests passed on SM100, with 3 architecture-specific skips. CuTe DSL 4.7: all 28 selected dynamic-host and pointer-combine cases passed. Native extension reused only after confirming native-source identity with the freshly built bc0054e binding. The immediately preceding bc0054e revision passed 213 focused native-facts/prepared/ABI/combine/decode tests plus 211 split/paged regressions, including other prefill flavors and quantized combine callers. Its three SM107 Int64 ABI cases also passed independently on Rubin. The only subsequent production change is the D256 host branch revalidated above; unchanged coverage is reused explicitly. Final-head B200 ABBA: 8 dense/paged NHD/HND cases, D128/D256, selected split2 and D256 unsplit, all passed complete FP64 O/LSE checks, output-padding canaries and changed-input/poisoned-output CUDA Graph replay. Six padded-output split cases reduced host enqueue from 67–138 us to 50–57 us and captured GPU time by 7–18%; these include eliminating the old output copy. A second ABBA control with contiguous Stats confirms the unsplit finding. Final-head analytic shape-override probe: D128 and D256 prepared split plans, declared KV=1024 overridden to 512 with full-capacity storage retained, produced exact expected O=1 and LSE=log(512). This validates this prepared domain, not every fallback path discussed in #1152. Fresh-process persistent-cache check: compilation forbidden, both unit/nonunit page-table paths execute correctly across four batch/split cases using two reloaded artifacts; zero misses, bypasses, invalid entries or export failures.

Limitations: Author-triggered pipeline 68850105 is still running; its mirror commit was verified against the full f418927 head. The inspected SM107 failure summary contains 12 native backend NVRTC plan-construction failures; two inspected Python jobs each have the same four cuTile correlated-key failures seen in earlier pipelines. This is a prior-pipeline category comparison, not an independent nightly-baseline rerun or a clean-CI claim. No duplicate CI was requested. Performance is a bounded B200 component comparison, not a full shape sweep or FlashInfer/model benchmark. Independent local/remote probes used cuDNN 9.25.1.1; the author's separate 9.26 GA numbers were not substituted for these measurements.

Comment only: GitHub does not allow reviewing one's own PR with approval/request-changes.

@YangXu1990uiuc

Copy link
Copy Markdown
Collaborator Author

CI follow-up for f418927: pipeline 68850105 finished with 25 passed, 8 failed, 5 manual. SM100 SDPA, SM80/SM120 SDPA, GEMM and linear passed. The SM103 job's “Old Failure” label hides two new prepared-split capture failures alongside its native FP8 failures, so the whole job should not be waived as baseline noise.

Review update: P1, blocking approval — collecting a retired prepared plan can invalidate another graph's capture. This updates my earlier no-blocker conclusion with new CI-driven evidence; please address it before merging.

The new D256 prepared path owns raw DeviceBuffer allocations for its dummies. DeviceBuffer.__del__ synchronously calls cuMemFree. If Python collects a retired plan while another plan is being captured, those frees return CUDA error 900, which the finalizer ignores; the subsequent attention launch and capture_end fail with 901. This both aborts capture and loses the failed frees. The finalizer predates this PR, but moving D256 onto the prepared path newly exposes it there.

Independent SM100 controls, using two D256 split2 plans (BF16, B2/Hq8/Hkv2/Q4/KV1024), retaining the retired plan in a Python reference cycle and collecting it inside the other plan's capture:

  • Previous 50c2e549: capture, changed-input replay and complete O/LSE reference checks pass; no raw device frees during capture.
  • Current f418927: three cuMemFree calls return 900, then capture fails with 901.
  • Current head, moving only collection before capture: passes all reference/replay checks.

I also instrumented the new 18-case test with collection at the prepared execution boundary: 13 fail / 5 pass; draining garbage before capture gives 18 pass, with no device frees during capture. These controlled probes establish the lifecycle failure. The CI's two failures have the matching launch/capture-end stack, but that CI run itself was not instrumented to prove the first invalidating call.

Please make retired-plan cleanup safe around capture, for example by retaining/reusing the immutable dummy allocation owners or deferring their frees to a safe point. Pre-collecting garbage can stabilize the test, but a test-only workaround would leave the newly exposed runtime lifetime issue. This is approval-blocking because multi-plan capture can fail nondeterministically depending on collection timing; it is not an attention numerical error or a P0.

The remaining six Python jobs have the previously observed four cuTile correlated-key failures; SM107 has the previously observed 12 native NVRTC failures. SM103 additionally has 35 native FP8 launch failures that the CI triage labels pre-existing; I have not independently established their nightly baseline. No additional broad CI run was requested.

Codex bot review — model gpt-6-astra.

@YangXu1990uiuc

Copy link
Copy Markdown
Collaborator Author

Updated to a2814ba54 with capture-safe FE resource cleanup and common D256 inner-stride specialization. Focused correctness: 253 passed; CuTe DSL 4.7.0 floor: 29 passed. B200 full-output/Stats and replay validation: 56/56 records. The description includes the measured host/GPU tradeoffs.

@cudnn-ci-bot run frost python_tests

@YangXu1990uiuc

Copy link
Copy Markdown
Collaborator Author

@cudnn-ci-bot run frost python_tests

@cudnn-ci-bot

cudnn-ci-bot commented Sep 20, 2026

Copy link
Copy Markdown

🏁 Pipeline finished

SHA: a2814ba
Targets: frost, python_tests
Branch: cudnn-gh/pr-1151-a2814ba
Pipeline: 68921996
Last updated: 2026-09-20 19:00 UTC

26 passed, 7 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 - ✅ Passed
  • 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 - ❌ Old Failure (nightly failed)
  • py_test:dev:sm90 - ❌ Old Failure (nightly failed)
  • py_test:dev:sm100 - ❌ Old Failure (nightly failed)
  • py_test:rel:sm80 - ❌ Old Failure (nightly failed)
  • py_test:rel:sm90 - ❌ Old Failure (nightly failed)
  • py_test:rel:sm100 - ❌ Old Failure (nightly failed)

sanitizer_tests

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

triage

  • triage:ai - ✅ Passed

YangXu1990uiuc added a commit to YangXu1990uiuc/cudnn-frontend that referenced this pull request Sep 20, 2026

@YangXu1990uiuc YangXu1990uiuc left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Codex bot review · model: gpt-6-astra

Reviewed a2814ba54be7 against base b100e34239d4.

The capture-lifetime fix addresses my earlier approval-blocking P1: the original retired-plan reproducer now passes, and forced collection at the prepared execution boundary passes all 18 cases. Removing owned dummy buffers, detaching saved exception chains, and scoping native destruction under a restored capture mode make sense together. I found no remaining approval blocker in this follow-up, with one nonblocking test-portability issue below. The earlier small-grid D256 performance concern is now represented in the matrix and addressed by the common-stride specialization; the description appropriately retains the remaining original-baseline tradeoff. Comment-only; the existing approval remains in place.

[P2] Use a portable native layout in the new lifetime regression (source)

The unconditional L0 regression uses native ReLU with dim=[1,1,32,32] and stride=[1024,1024,32,1]. On both A100 and H100 with cuDNN 9.26.0.51, neither resource case reaches collection: graph.build() rejects the C=1 layout, while the additional pointwise engine is SM10x-only. Please use a supported native layout for this cross-architecture test. I independently verified dim=[1,32,1,32], stride=[1024,1,1024,32] for both X and Y, with matching tensor views, on A100: collecting either resource during global capture, replay, subsequent native execution, and actual GLOBAL/THREAD_LOCAL mode restoration all pass. This preserves the lifetime detector rather than losing the case to an unconditional architecture skip.

Evidence: Exact a2814ba source and freshly rebuilt native extension, PyTorch 2.13.0+cu130, cuDNN 9.26.0.51: the new module reports 2 failed / 2 passed on H100; both resource cases also fail at the same graph construction on A100. The unchanged module passes 4/4 on SM100. A separate A100 native-layout control passes both resource kinds under both initial thread modes. The failure is before capture, not a recurrence of the cleanup defect. Attribution: Introduced by the new cross-architecture lifetime test in this revision; the underlying backend layout restriction is pre-existing.

Validation: Rebuilt the native binding from a2814ba and verified the loaded Python/native paths. On SM100 with cuDNN 9.26.0.51 and the minimum CuTe DSL 4.7.0, prepared THD/dense/split, geometry, pointer-ABI and D256 decode suites: 147 passed, 3 architecture skips. These include nonunit page-table and output strides through the general branch. Original two-plan D256 split2 cyclic-GC reproducer: passes without pre-draining garbage, with full FP64 O/LSE and changed-input/poisoned-output replay checks. All 18 prepared split capture cases also pass with gc.collect() injected at the prepared execution boundary; no failed device frees during capture. This closes the earlier P1. Native lifetime module on SM100: 4 passed. A100 independent native-layout control: device-buffer and owned-backend-graph collection both preserve capture/replay and later native execution, and restore the real thread capture mode from both GLOBAL and THREAD_LOCAL starting states. The scoped exchange follows CUDA's documented push/pop model. Default-path dispatch suite on A100 with FROST opt-in disabled: 61 passed, including chained backend-exception lifetime and repeated-build diagnostics. A bounded local SM100 ABBA comparison against f418927, using each revision's corresponding native binding, checked dense and paged-NHD D256 unsplit execution. Both arms passed full O/LSE references and changed-input replay; captured GPU time improved in both cases, with no consistent material host-enqueue regression. GC was excluded equally from timing only; the separate forced-GC tests above validate lifetime behavior.

Limitations: Owner-triggered pipeline 68921996 is still running. Its mirrored commit explicitly identifies the full a2814ba head. No duplicate CI was requested; pending architecture lanes are not counted as passes. The timing spot check covers two local SM100 component cases. The broader final-head B200 matrix in the PR description remains author-reported; I did not repeat that allocation or establish a uniform improvement over 50c2e54.

Comment only: GitHub does not allow reviewing one's own PR with approval/request-changes.

@YangXu1990uiuc

Copy link
Copy Markdown
Collaborator Author

Pipeline 68921996 has finished for a2814ba. The SM80/SM100/SM103/SM120 FROST SDPA lanes, SM100 linear/GEMM, builds/analysis and C++ sanitizer lanes passed; SM103 reported 5,921 passed / 1,904 skipped.

The remaining reds need to be distinguished despite the summary's blanket “Old Failure” labels:

  • New test-fixture issue: the inspected SM90 Python lane has the two native C=1 lifetime-test failures from the review, alongside four existing cuTile correlated-key failures. Please retain the lifetime coverage using a supported layout.
  • Unchanged dynamic-shape fixture: the SM100 Python lane crashed at the final batch=2 override in test_block_scale_quantize_matmul_dynamic_shape[1-1024-1024-1024]. Both scale-buffer allocations still use the original b=1, although their overridden descriptors require two batches. This file is identical to the merge base. An independent local control changing only those two allocations to dynamic_shape["b"] completed all 11 overrides, including batch=2, on SM100/cuDNN 9.26.0.51. This is a separate pre-existing fixture defect; the undersized-buffer case was not rerun locally.
  • Rubin lane: 12 native ragged-Stats NVRTC compilation failures match the previously observed failure category; 3,229 passed / 1,963 skipped.

The capture-lifetime blocker remains resolved by the focused tests and the now-passing FROST lanes. The new lifetime-test layout issue remains actionable; this is not an all-green Python run.

Codex bot review — model gpt-6-astra.

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

Labels

area:frost area:global_attention cat-perf-bug Performance regressions or cases where behavior is correct but too slow. orig-nv-eng Reported or requested by NVIDIA engineering.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants