Skip to content

Add FROST engines - #476

Merged
Anerudhan merged 2 commits into
developfrom
feat/frost_develop
Aug 4, 2026
Merged

Add FROST engines#476
Anerudhan merged 2 commits into
developfrom
feat/frost_develop

Conversation

@Anerudhan

@Anerudhan Anerudhan commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

cudnn frost engines

Open source cudnn engines written using cutlass-primitives.

What's included

  • FROST / cuTile engine implementations, kernel templates, and engine routing
  • GDN cuTile path
  • GEMM and linear-attention benchmarks
  • Accompanying Python tests

With contributions from cudnn team

Summary by CodeRabbit

  • New Features
    • Added FROST acceleration for GEMM, grouped MoE matmul, fused epilogues, linear attention, and SDPA workloads.
    • Added support for FP4/FP8 and MXFP8 data formats, variable-length sequences, recurrent states, masking, and quantized outputs.
    • Added unified plan discovery, ranking, selection, fallback, workspace handling, and execution reporting.
    • Added standalone benchmarks and examples for performance and correctness validation.
  • Documentation
    • Expanded guidance for FROST engines, routing, configuration, linear attention, and GEMM integration.
  • Breaking Changes
    • Removed FFT-based Causal Conv1d APIs and documentation.

Port the FROST engine work from the internal cudnn_frontend
frost_devel branch (GitLab MR !2310) onto feat/frost_develop.

Includes the FROST/cuTile engine implementations and routing, the
GDN cuTile path, GEMM and linear-attention benchmarks, and the
accompanying Python tests.

The internal ci/ directory is intentionally excluded: it has no
counterpart in this repository.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 82f47f63-63d6-4ee3-aed4-5a6df9c756d3

📥 Commits

Reviewing files that changed from the base of the PR and between b5a068d and 3a66e46.

📒 Files selected for processing (212)
  • README.md
  • benchmark/gemm/frost/benchmark_block_scale_matmul.py
  • benchmark/gemm/frost/benchmark_block_scale_matmul_swiglu.py
  • benchmark/gemm/frost/benchmark_compilation_time.py
  • benchmark/gemm/frost/benchmark_matmul.py
  • benchmark/gemm/frost/benchmark_matmul_mixed_input.py
  • benchmark/gemm/frost/benchmark_matmul_swiglu.py
  • benchmark/gemm/frost/benchmark_moe_block_scale_matmul.py
  • benchmark/gemm/frost/benchmark_moe_block_scale_matmul_swiglu.py
  • benchmark/gemm/frost/benchmark_moe_grouped_matmul.py
  • benchmark/gemm/frost/benchmark_moe_grouped_matmul_models.py
  • benchmark/gemm/frost/benchmark_moe_grouped_matmul_swiglu.py
  • benchmark/linear_attention/Dockerfile
  • benchmark/linear_attention/README.md
  • benchmark/linear_attention/benchmark_single_linear_attention.py
  • docs/operations/CausalConv1d.md
  • docs/operations/FFTCausalConv1d.md
  • docs/python_graph_and_execution_backends.md
  • include/cudnn_frontend/node/scaled_dot_product_flash_attention.h
  • include/cudnn_frontend/plans.h
  • include/cudnn_frontend_shim.h
  • llms.txt
  • pyproject.toml
  • python/cudnn/README.md
  • python/cudnn/__init__.py
  • python/cudnn/_pygraph.py
  • python/cudnn/datatypes.py
  • python/cudnn/engines/__init__.py
  • python/cudnn/engines/base.py
  • python/cudnn/engines/engine_ids.py
  • python/cudnn/engines/heuristics.py
  • python/cudnn/engines/manifest.py
  • python/cudnn/engines/router.py
  • python/cudnn/frost/README.md
  • python/cudnn/frost/__init__.py
  • python/cudnn/frost/buffers.py
  • python/cudnn/frost/device.py
  • python/cudnn/frost/occupancy.py
  • python/cudnn/frost/template_loader.py
  • python/cudnn/frost/tile_dsl/__init__.py
  • python/cudnn/frost/tile_dsl/barrier.py
  • python/cudnn/frost/tile_dsl/constants.py
  • python/cudnn/frost/tile_dsl/handles.py
  • python/cudnn/frost/tile_dsl/mask.py
  • python/cudnn/frost/tile_dsl/mma.py
  • python/cudnn/frost/tile_dsl/pointwise.py
  • python/cudnn/frost/tile_dsl/regtile.py
  • python/cudnn/frost/tile_dsl/rope.py
  • python/cudnn/frost/tile_dsl/scheduler.py
  • python/cudnn/frost/tile_dsl/swizzle.py
  • python/cudnn/frost/tile_dsl/tma.py
  • python/cudnn/frost/tile_dsl/tmem.py
  • python/cudnn/frost/workspace.py
  • python/cudnn/gemm/cutedsl/dense/proj_rope_mxfp8/gemm_proj_rope_mxfp8.py
  • python/cudnn/gemm/frost/__init__.py
  • python/cudnn/gemm/frost/compiler.py
  • python/cudnn/gemm/frost/dtypes.py
  • python/cudnn/gemm/frost/engine.py
  • python/cudnn/gemm/frost/epilogue_codegen.py
  • python/cudnn/gemm/frost/fusion_ir.py
  • python/cudnn/gemm/frost/graph_analyzer.py
  • python/cudnn/gemm/frost/kernel_registry.py
  • python/cudnn/gemm/frost/kernel_templates/sm100_block_scale_matmul_1ctamma.py
  • python/cudnn/gemm/frost/kernel_templates/sm100_block_scale_matmul_1ctamma_static.py
  • python/cudnn/gemm/frost/kernel_templates/sm100_block_scale_matmul_2ctamma.py
  • python/cudnn/gemm/frost/kernel_templates/sm100_block_scale_matmul_2ctamma_static.py
  • python/cudnn/gemm/frost/kernel_templates/sm100_matmul_1ctamma.py
  • python/cudnn/gemm/frost/kernel_templates/sm100_matmul_1ctamma_static.py
  • python/cudnn/gemm/frost/kernel_templates/sm100_matmul_2ctamma.py
  • python/cudnn/gemm/frost/kernel_templates/sm100_matmul_2ctamma_static.py
  • python/cudnn/gemm/frost/kernel_templates/sm100_matmul_mainloop_1ctamma.py
  • python/cudnn/gemm/frost/kernel_templates/sm100_matmul_mainloop_2ctamma.py
  • python/cudnn/gemm/frost/kernel_templates/sm100_moe_grouped_block_scale_matmul_fwd_1ctamma.py
  • python/cudnn/gemm/frost/kernel_templates/sm100_moe_grouped_block_scale_matmul_fwd_2ctamma.py
  • python/cudnn/gemm/frost/kernel_templates/sm100_moe_grouped_matmul_fwd_1ctamma.py
  • python/cudnn/gemm/frost/kernel_templates/sm100_moe_grouped_matmul_fwd_2ctamma.py
  • python/cudnn/gemm/frost/kernel_templates/sm103_block_scale_matmul_1ctamma.py
  • python/cudnn/gemm/frost/kernel_templates/sm103_block_scale_matmul_2ctamma.py
  • python/cudnn/gemm/frost/tile_config.py
  • python/cudnn/gemm/reference/__init__.py
  • python/cudnn/gemm/reference/reference_matmul_engine.py
  • python/cudnn/graph_types.py
  • python/cudnn/linear_attention/__init__.py
  • python/cudnn/linear_attention/cutile/__init__.py
  • python/cudnn/linear_attention/cutile/gdn_engine.py
  • python/cudnn/linear_attention/cutile/kda_engine.py
  • python/cudnn/linear_attention/cutile/kernels/__init__.py
  • python/cudnn/linear_attention/cutile/kernels/common.py
  • python/cudnn/linear_attention/cutile/kernels/gdn_chunk_cutile.py
  • python/cudnn/linear_attention/cutile/kernels/kda_chunk_cutile.py
  • python/cudnn/linear_attention/engine_utils.py
  • python/cudnn/linear_attention/frost/__init__.py
  • python/cudnn/linear_attention/frost/common/__init__.py
  • python/cudnn/linear_attention/frost/common/head_reduce.py
  • python/cudnn/linear_attention/frost/common/split_k.py
  • python/cudnn/linear_attention/frost/common/thd.py
  • python/cudnn/linear_attention/frost/gdn2_engine.py
  • python/cudnn/linear_attention/frost/gdn_engine.py
  • python/cudnn/linear_attention/frost/kda_engine.py
  • python/cudnn/linear_attention/frost/kernel/__init__.py
  • python/cudnn/linear_attention/frost/kernel/gdn2_bprop_config.py
  • python/cudnn/linear_attention/frost/kernel/gdn2_bprop_f16.py
  • python/cudnn/linear_attention/frost/kernel/gdn2_prefill_config.py
  • python/cudnn/linear_attention/frost/kernel/gdn2_prefill_f16.py
  • python/cudnn/linear_attention/frost/kernel/gdn_bprop_config.py
  • python/cudnn/linear_attention/frost/kernel/gdn_bprop_f16.py
  • python/cudnn/linear_attention/frost/kernel/gdn_prefill_config.py
  • python/cudnn/linear_attention/frost/kernel/gdn_prefill_f16.py
  • python/cudnn/linear_attention/frost/kernel/kda_bprop_config.py
  • python/cudnn/linear_attention/frost/kernel/kda_bprop_f16.py
  • python/cudnn/linear_attention/frost/kernel/kda_prefill_config.py
  • python/cudnn/linear_attention/frost/kernel/kda_prefill_f16.py
  • python/cudnn/linear_attention/ops/__init__.py
  • python/cudnn/linear_attention/ops/gdn.py
  • python/cudnn/linear_attention/ops/gdn2.py
  • python/cudnn/linear_attention/ops/kda.py
  • python/cudnn/ops/__init__.py
  • python/cudnn/ops/causal_conv1d.py
  • python/cudnn/ops/fft_causal_conv1d.py
  • python/cudnn/sdpa/fwd/__init__.py
  • python/cudnn/sdpa/fwd/api_dsl.py
  • python/cudnn/sdpa/fwd/config_sm100.py
  • python/cudnn/sdpa/fwd/config_sm120.py
  • python/cudnn/sdpa/fwd/engine.py
  • python/cudnn/sdpa/fwd/engines.py
  • python/cudnn/sdpa/fwd/kernels/__init__.py
  • python/cudnn/sdpa/fwd/kernels/_common_sm100.py
  • python/cudnn/sdpa/fwd/kernels/prefill_d128_f16_sm100.py
  • python/cudnn/sdpa/fwd/kernels/prefill_d128_fp8_sm100.py
  • python/cudnn/sdpa/fwd/kernels/prefill_d128_mxfp8_sm100.py
  • python/cudnn/sdpa/fwd/kernels/prefill_d256_f16_sm100.py
  • python/cudnn/sdpa/fwd/kernels/prefill_d512_f16_sm100.py
  • python/cudnn/sdpa/fwd/kernels/prefill_f16_sm120.py
  • python/cudnn/sdpa/fwd/kernels/thd_sm100.py
  • python/cudnn/sdpa/graph_analyzer.py
  • python/pycudnn.cpp
  • samples/cpp/CMakeLists.txt
  • samples/cpp/causal_conv1d/fft_causal_conv1d.cpp
  • samples/python/66_fft_causal_conv1d_forward.ipynb
  • samples/python/67_fft_causal_conv1d_backward.ipynb
  • skills/cutedsl-kernel-integration/references/integration-pattern.md
  • test/python/conftest.py
  • test/python/frost_routing.py
  • test/python/gemm/frost/conftest.py
  • test/python/gemm/frost/examples/00_matmul.py
  • test/python/gemm/frost/examples/01_matmul_epilogue_fusion.py
  • test/python/gemm/frost/examples/02_matmul_mainloop_fusion.py
  • test/python/gemm/frost/examples/03_matmul_mixed_input_type.py
  • test/python/gemm/frost/examples/04_matmul_swiglu.py
  • test/python/gemm/frost/examples/05_moe_grouped_matmul_fwd.py
  • test/python/gemm/frost/examples/06_moe_grouped_matmul_fwd_swiglu.py
  • test/python/gemm/frost/gemm_test_utils.py
  • test/python/gemm/frost/test_block_scale_matmul.py
  • test/python/gemm/frost/test_block_scale_matmul_swiglu.py
  • test/python/gemm/frost/test_frontend_integration.py
  • test/python/gemm/frost/test_matmul.py
  • test/python/gemm/frost/test_matmul_epilogue_fusion.py
  • test/python/gemm/frost/test_matmul_mainloop_fusion.py
  • test/python/gemm/frost/test_matmul_swiglu.py
  • test/python/gemm/frost/test_moe_grouped_block_scale_matmul_fwd.py
  • test/python/gemm/frost/test_moe_grouped_block_scale_matmul_fwd_swiglu.py
  • test/python/gemm/frost/test_moe_grouped_matmul_fwd.py
  • test/python/gemm/frost/test_moe_grouped_matmul_fwd_epilogue_fusion.py
  • test/python/gemm/frost/test_moe_grouped_matmul_fwd_swiglu.py
  • test/python/gemm/frost/test_multi_gemm.py
  • test/python/gemm/frost/test_stream_respect.py
  • test/python/gemm/frost/test_tile_select_analytic.py
  • test/python/linear_attention/__init__.py
  • test/python/linear_attention/common.py
  • test/python/linear_attention/conftest.py
  • test/python/linear_attention/cutile/__init__.py
  • test/python/linear_attention/cutile/conftest.py
  • test/python/linear_attention/cutile/test_gdn_bprop.py
  • test/python/linear_attention/cutile/test_gdn_fprop.py
  • test/python/linear_attention/cutile/test_kda_bprop.py
  • test/python/linear_attention/cutile/test_kda_fprop.py
  • test/python/linear_attention/frost/__init__.py
  • test/python/linear_attention/frost/conftest.py
  • test/python/linear_attention/frost/test_gdn2_bprop_kernel.py
  • test/python/linear_attention/frost/test_gdn2_prefill_kernel.py
  • test/python/linear_attention/frost/test_gdn_bprop_kernel.py
  • test/python/linear_attention/frost/test_gdn_prefill_kernel.py
  • test/python/linear_attention/frost/test_kda_bprop_kernel.py
  • test/python/linear_attention/frost/test_kda_prefill_kernel.py
  • test/python/linear_attention/ops/__init__.py
  • test/python/linear_attention/ops/test_gdn2_op.py
  • test/python/linear_attention/ops/test_gdn_op.py
  • test/python/linear_attention/ops/test_kda_op.py
  • test/python/linear_attention/reference_gdn.py
  • test/python/linear_attention/reference_gdn2.py
  • test/python/linear_attention/reference_kda.py
  • test/python/sdpa/fp16.py
  • test/python/sdpa/fp8.py
  • test/python/sdpa/frost/conftest.py
  • test/python/sdpa/frost/test_sdpa_frontend_integration.py
  • test/python/sdpa/frost/test_sdpa_fwd_dsl_sm100.py
  • test/python/sdpa/frost/test_sdpa_fwd_dsl_sm120.py
  • test/python/sdpa/frost/test_sdpa_fwd_fp8_sm100.py
  • test/python/sdpa/frost/test_sdpa_fwd_mxfp8_sm100.py
  • test/python/sdpa/frost/test_sdpa_graph_analyzer.py
  • test/python/sdpa/frost/test_sdpa_stream_respect.py
  • test/python/sdpa/helpers.py
  • test/python/sdpa/mxfp8.py
  • test/python/sdpa/mxfp8_quant.py
  • test/python/sdpa/random_config.py
  • test/python/test_causal_conv1d.py
  • test/python/test_engine_router.py
  • test/python/test_fft_causal_conv1d.py
  • test/python/test_graph_native.py
  • test/python/test_mhas_v2.py
  • test/python/test_mxfp8_quant.py
  • test/python/test_native_backend_lowering.py

📝 Walkthrough

Walkthrough

This PR adds three new opt-in OSS execution engines under a unified cuDNN Python router: FROST GEMM (CuTe-DSL kernels for matmul, block-scale, MoE, SwiGLU), FROST/cuTile linear attention (GDN, KDA, GDN-2), and FROST SDPA-forward (SM100/SM120). It adds a segmented engine-ID namespace, manifest-based lazy engine discovery, and a unified graph.plans list combining Python and backend plans. It removes the FFT causal-convolution API, bindings, and FP64 support in causal convolution, and adds extensive benchmarks and tests for the new engines.

Changes

Engine Routing Infrastructure

Layer / File(s) Summary
Unified plan list and manifest
python/cudnn/_pygraph.py, python/cudnn/engines/*.py, python/cudnn/datatypes.py, python/cudnn/graph_types.py, docs/python_graph_and_execution_backends.md
Introduces one ranked graph.plans list combining Python and backend plan entries, a segmented engine-ID namespace, manifest-based lazy engine discovery, and updated router/heuristics logic.
Router regression tests
test/python/test_engine_router.py, test_graph_native.py, test_native_backend_lowering.py
Reworks tests around out-of-tree engine IDs and the unified ranked plan list.

FROST Tile-DSL Core Infrastructure

Layer / File(s) Summary
Device/buffer/workspace helpers
python/cudnn/frost/{buffers,device,occupancy,template_loader,workspace}.py
Adds DLPack-based device-buffer exchange, occupancy tables, template specialization, and workspace carving.
CuTe tile-DSL primitives
python/cudnn/frost/tile_dsl/*.py
Adds barrier, MMA, TMA, swizzle, pointwise, regtile, scheduler, rope, and handle primitives shared across FROST kernels.

FROST GEMM Engine

Layer / File(s) Summary
Fusion IR, analyzer, engine
python/cudnn/gemm/frost/{fusion_ir,graph_analyzer,dtypes,epilogue_codegen,engine}.py
Defines the epilogue fusion contract, analyzes native cuDNN graphs into fusion chains, and implements the FrostGemmEngine contract.
Kernel registry, tile config, compiler, kernel templates
python/cudnn/gemm/frost/{kernel_registry,tile_config,compiler}.py, kernel_templates/*.py, gemm/cutedsl/dense/proj_rope_mxfp8/*
Selects and compiles SM100/SM103 CuTe-DSL matmul, block-scale, MoE, and mainloop-fusion kernels.
Benchmarks
benchmark/gemm/frost/*.py
Adds benchmarks for matmul, block-scale matmul, SwiGLU, mixed-input, MoE variants, and compilation time.
Tests and examples
test/python/gemm/frost/*.py
Adds comprehensive analyzer, codegen, and end-to-end numerical test coverage plus runnable examples.

FROST/cuTile Linear Attention Engines

Layer / File(s) Summary
cuTile engines and kernels
python/cudnn/linear_attention/cutile/*.py
Adds GdnCuTileEngine/KdaCuTileEngine and their chunked forward/backward CuTe kernels.
FROST engines and CUTLASS kernels
python/cudnn/linear_attention/frost/*.py
Adds GdnFrostEngine, KdaFrostEngine, Gdn2FrostEngine, split-K/THD helpers, and SM100 prefill/backward kernels.
Custom PyTorch operators
python/cudnn/linear_attention/ops/*.py
Adds gated_delta_net, kimi_delta_attention, and gated_delta_net_v2 custom ops with autograd support.
Benchmarks
benchmark/linear_attention/*
Adds a Docker image and a single-linear-attention benchmark comparing cuDNN and FLA.
Tests
test/python/linear_attention/*
Adds fp64 reference implementations and cuTile/FROST/ops test coverage.

FROST SDPA-Forward Engine

Layer / File(s) Summary
Capabilities, analyzer, DSL lowering
python/cudnn/sdpa/fwd/{engine,engines,api_dsl,config_sm100,config_sm120}.py, python/cudnn/sdpa/graph_analyzer.py
Defines capability specs, eligibility analysis, and DSL adapter compilation for SM100/SM120 SDPA.
CuTe SDPA kernels
python/cudnn/sdpa/fwd/kernels/*.py
Adds SM100 d128/d256/d512 (FP16/FP8/MXFP8) and SM120 prefill kernels.
Tests and routing annotations
test/python/sdpa/frost/*, test/python/sdpa/{fp16,fp8,mxfp8,helpers,mxfp8_quant,random_config}.py, test_mhas_v2.py, test_mxfp8_quant.py
Adds FROST SDPA tests, a torch-only MXFP8 quantizer replacement, and FROST-routing test annotations.

FFT Causal Conv1d Removal

Layer / File(s) Summary
Remove FFT causal-conv bindings and FP64 support
include/cudnn_frontend_shim.h, python/pycudnn.cpp, python/cudnn/ops/causal_conv1d.py, llms.txt, docs/operations/CausalConv1d.md, test/python/test_causal_conv1d.py
Removes FFT causal-convolution shims/bindings, removes FP64 dtype support in causal convolution, and updates docs and tests.

Test Infrastructure and Docs

Layer / File(s) Summary
Shared pytest infra
test/python/conftest.py, test/python/frost_routing.py, README.md, pyproject.toml
Adds GPU-memory gating, FROST-routing summary reporting, and updated top-level engine docs.

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

Sequence Diagram(s)

sequenceDiagram
  participant User as Caller
  participant Graph as pygraph
  participant Router
  participant Manifest
  participant FrostEngine as FrostGemmEngine
  participant Backend as cuDNN Backend

  User->>Graph: build_plans() / execute()
  Graph->>Manifest: engines_for(graph, sm)
  Manifest-->>Graph: candidate engines
  Graph->>Router: plan(graph, engines)
  Router->>FrostEngine: check_support(graph)
  FrostEngine-->>Router: PlanConfig or decline
  Router->>Backend: backend_plan_entries(graph)
  Backend-->>Router: ranked backend plans
  Router-->>Graph: unified graph.plans list
  User->>Graph: execute(variant_pack)
  Graph->>FrostEngine: build_plan / __call__(uid_to_data, workspace, stream)
  FrostEngine->>Backend: (if declined) fall through
  FrostEngine-->>User: output tensors
Loading

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

Possibly related PRs

  • NVIDIA/cudnn-frontend#437: Removes the same FFT causal-convolution bindings, documentation, exports, samples, and tests that PR #437 originally added.
  • NVIDIA/cudnn-frontend#479: Removes the same FFT causal-convolution bindings, shims, documentation, and tests as PR #479.

Suggested labels: mod-cutedsl, mod-backend

Suggested reviewers: yangxu1990uiuc, jhjpark

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/frost_develop

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

@Anerudhan Anerudhan self-assigned this Aug 4, 2026
@Anerudhan Anerudhan added this to the Frontend 1.27.0 milestone Aug 4, 2026
@Anerudhan Anerudhan added cat-feature Requests for new functionality, APIs, examples, or behavior improvements. orig-nv-eng Reported or requested by NVIDIA engineering. and removed mod-frost labels Aug 4, 2026
@Anerudhan Anerudhan changed the title Add GDN cuTile and FROST engines Add FROST engines Aug 4, 2026

@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.

LFG!

This reverts commit b5a068d.

(cherry picked from commit 05533fc)

Co-authored-by: Ye Liu <yeliu@nvidia.com>
@Anerudhan
Anerudhan marked this pull request as ready for review August 4, 2026 21:03
@Anerudhan
Anerudhan merged commit ac9356f into develop Aug 4, 2026
1 check was pending
@Anerudhan Anerudhan mentioned this pull request Aug 6, 2026
@coderabbitai coderabbitai Bot mentioned this pull request Aug 6, 2026
3 tasks
vedaanta added a commit to vedaanta/cudnn-frontend that referenced this pull request Aug 10, 2026
… overlapping strides

- _thd_view validates the runtime buffer against its declaration before
  reinterpreting storage: dtype/device must match and the base address must
  be 16-byte aligned (TMA global-address rule / assumed_align=16);
  as_strided already rejects views past the underlying allocation.
- _thd_check_strides_native additionally requires covering (non-overlapping)
  strides — head >= d, token >= heads*head — matching the SM120 kernel's
  is_layout_supported, so sub-dense declarations are declined at
  check_support instead of failing at the per-execute compile (or racing on
  O writes on SM100).
- Kernel _fake_bshd guards: the head dim must be innermost-contiguous;
  d256/d512 validate the O stride at BPE_O (the O storage dtype byte size).
- Clearer SM120 layout-rejection message (the entry validator accepts padded
  storage now; the text still demanded compact).

The THD host-prep stream binding flagged in the same review round is a
pre-existing issue (NVIDIA#476) and is split into a separate PR.

Addresses CodeRabbit review feedback on NVIDIA#526.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
vedaanta added a commit that referenced this pull request Aug 11, 2026
…6 fwd kernels (#526)

* frost(sdpa): native THD stride support in the SM100/SM120 f16 fwd kernels; decline what TMA cannot express

A THD tensor may declare a wider token stride than the packed h*d — e.g.
a K/V view of a kv-interleaved [T, 2, H, D] buffer (token stride 2*h*d),
the layout torch.nn.attention.varlen users produce by slicing a fused KV
projection. The THD lowerings rebuilt packed (1, T, H, D) views with
hardcoded strides, so such graphs were claimed and silently mis-addressed
(100% of O wrong on both sdpa_fwd_prefill_sm120 and the sm100 flavors;
caught by PR #516's fuzz coverage and PyTorch's own varlen suite).

Native support, no fallback (AGENTS Hard Rule 2):

- compile() on all five f16 kernels (sm120, sm100 d128/d192_d128/d256/
  d512) takes optional caller-declared (batch, seq, head, elem) strides
  per tensor (lru cache-key); None keeps the compact specialization
  bit-for-bit. Strided fakes via make_fake_tensor, validated against the
  TMA 16-byte global-stride rule.
- SM120: kv_tma_desc reads the tensor's strides instead of recomputing
  packed ones (Q/O offset math was already layout-driven); the entry
  validator accepts padded 16-byte-granular BSHD storage (compact = the
  equality special case).
- SM100: the Q/K/V/O TMA descriptors are built from the tensor views, so
  declared strides flow in unchanged; the THD O-descriptor builder steps
  per-batch bases by O's declared seq-axis stride (o_tensor.stride[1]).
- Adapters bind declared-stride (1, T, H, D) views directly. What TMA
  cannot express is REJECTED in check_support (NotImplementedError naming
  the offending strides), so the Router falls back to an engine that
  honors the declaration: non-innermost-contiguous head dim, or
  token/head strides that are not multiples of 8 elements (sub-
  granularity strides also violate the graph API's pointer-alignment
  contract for the backend, so declining is correct, not conservative).
- The SM120 FP8 THD path (#509) keeps the packed contract for now:
  non-packed declarations are declined (_thd_check_strides_packed);
  extending native strides there is tracked as a follow-up.

Verified (torch nightly cu132, ToT develop + PR #516's fuzz tests):
gapped seeded repros pass with the frost engines serving natively on
cc 10.0 (sm100) and RTX 5080 (sm120); 128-test fwd ragged L0 sweep slice
green on cc 10.0 (all four sm100 flavors) and 84-test slice on sm120;
ex-ops suite incl. kv-interleaved views 11/11 on both; dense fwd slice
182 passed (dense compile paths pass no strides -> unchanged); packed
THD configs bit-for-bit unchanged.

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

* docs(agents): Hard Rule 2 — serve the declared layout natively or decline, never adapt

Closes the loophole Rule 1's letter leaves open: adapter-side
normalization copies that make an unsupported layout runnable. Workspace
carving does not legitimize a data-tensor copy (the carve exemption is
for metadata and dead-slot dummies), the dense path's grandfathered
normalization is not a license for new ones, and whatever check_support
accepts the kernel must address natively.

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

* frost(sdpa): review hardening — validate runtime THD buffers, decline overlapping strides

- _thd_view validates the runtime buffer against its declaration before
  reinterpreting storage: dtype/device must match and the base address must
  be 16-byte aligned (TMA global-address rule / assumed_align=16);
  as_strided already rejects views past the underlying allocation.
- _thd_check_strides_native additionally requires covering (non-overlapping)
  strides — head >= d, token >= heads*head — matching the SM120 kernel's
  is_layout_supported, so sub-dense declarations are declined at
  check_support instead of failing at the per-execute compile (or racing on
  O writes on SM100).
- Kernel _fake_bshd guards: the head dim must be innermost-contiguous;
  d256/d512 validate the O stride at BPE_O (the O storage dtype byte size).
- Clearer SM120 layout-rejection message (the entry validator accepts padded
  storage now; the text still demanded compact).

The THD host-prep stream binding flagged in the same review round is a
pre-existing issue (#476) and is split into a separate PR.

Addresses CodeRabbit review feedback on #526.

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

* frost(sdpa): make the THD native-stride gate dtype-aware (16 // itemsize)

The gate hardcoded the TMA 16-byte global-stride rule as 8 elements, the
f16/bf16 case. It lives in the shared base class, so express the quantum
in the tensor's own element units — 8 at 2 B/elem, 16 at 1 B/elem (fp8),
4 at 4 B/elem — per descriptor, so mixed-precision declarations check each
tensor at its own dtype. No behavior change for the f16 paths this PR
enables; the fp8 native-stride follow-up (#537) inherits the correct
quantum for free.

Suggested by @Aneureka in review.

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

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
vedaanta added a commit to vedaanta/cudnn-frontend that referenced this pull request Aug 11, 2026
The THD execute paths do torch host work before the kernel launch — the
[seq_kv | cu_q | cu_k] metadata allocation + D2H length reads + one-shot
H2D upload (SM100 and the shared SM120 _thd_pack), the per-sequence
O-descriptor buffer (SM100), the dummy-sink buffer (SM100), and the cached
seq_q dummy's first-use allocation (SM120). These enqueued on torch's
CURRENT stream while the kernel launches on the stream carried by the
execute-time handle (ExecutionContext.stream): when the two differ, the
prep and the kernel race.

Run the prep inside _torch_stream_context (the same helper the fp8/mxfp8
amax paths already use), and resolve the launch stream BEFORE _thd_pack in
both SM120 callers. Allocations happen inside the context too, so
caching-allocator blocks are stream-tagged to the stream that uses them.

Pre-existing since the FROST engines landed (NVIDIA#476); split out of the NVIDIA#526
review round to keep that PR scoped to native THD stride support. Only
direct graph-API users with an explicit handle stream are affected — the
PyTorch integration launches on torch's current stream.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
vedaanta added a commit to vedaanta/cudnn-frontend that referenced this pull request Aug 11, 2026
Two per-execute fill kernels on the THD execute hot path initialized
buffers whose contents provably do not matter:

- The per-sequence O-descriptor buffer: the kernel's builder pass copies
  every qword of each slot from the base descriptor (then patches
  address/extent) before the fence and before any consumer read; stale
  workspace bytes never survive to a read. The +16-qword tail is never
  read at all.
- The dummy sinks buffer: the sinks slot is always part of the kernel ABI,
  but CFG.HAS_SINK is a compile-time fold — when the graph declares no
  sink the kernel never reads the buffer (and execute() enforces
  has_sink <=> sinks is not None, so the dummy only exists in the
  never-read case).

Both fills date to the original FROST landing (NVIDIA#476) as belt-and-braces.
Rule 1: no adapter-side fills on the execute hot path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
vedaanta added a commit to vedaanta/cudnn-frontend that referenced this pull request Aug 13, 2026
The THD execute paths do torch host work before the kernel launch — the
[seq_kv | cu_q | cu_k] metadata allocation + D2H length reads + one-shot
H2D upload (SM100 and the shared SM120 _thd_pack), the per-sequence
O-descriptor buffer (SM100), the dummy-sink buffer (SM100), and the cached
seq_q dummy's first-use allocation (SM120). These enqueued on torch's
CURRENT stream while the kernel launches on the stream carried by the
execute-time handle (ExecutionContext.stream): when the two differ, the
prep and the kernel race.

Run the prep inside _torch_stream_context (the same helper the fp8/mxfp8
amax paths already use), and resolve the launch stream BEFORE _thd_pack in
both SM120 callers. Allocations happen inside the context too, so
caching-allocator blocks are stream-tagged to the stream that uses them.

Pre-existing since the FROST engines landed (NVIDIA#476); split out of the NVIDIA#526
review round to keep that PR scoped to native THD stride support. Only
direct graph-API users with an explicit handle stream are affected — the
PyTorch integration launches on torch's current stream.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
vedaanta added a commit to vedaanta/cudnn-frontend that referenced this pull request Aug 13, 2026
…tor scratch (SM100)

A per-execute fill kernel on the THD execute hot path initialized the
per-sequence O TMA-descriptor buffer, whose contents provably do not
matter: the kernel's builder pass copies every qword of each sequence's
slot from the base descriptor (then patches address/extent) before the
fence and before any consumer read — stale workspace bytes never survive
to a read. The +16-qword tail is never read at all.

The fill dates to the original FROST landing (NVIDIA#476) as belt-and-braces.
Rule 1: no adapter-side fills on the execute hot path.

(The matching dummy-sinks fill removal is split into its own PR.)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
vedaanta added a commit to vedaanta/cudnn-frontend that referenced this pull request Aug 13, 2026
The THD execute paths do torch host work before the kernel launch — the
[seq_kv | cu_q | cu_k] metadata allocation + D2H length reads + one-shot
H2D upload (SM100 and the shared SM120 _thd_pack), the per-sequence
O-descriptor buffer (SM100), the dummy-sink buffer (SM100), and the cached
seq_q dummy's first-use allocation (SM120). These enqueued on torch's
CURRENT stream while the kernel launches on the stream carried by the
execute-time handle (ExecutionContext.stream): when the two differ, the
prep and the kernel race.

Run the prep inside _torch_stream_context (the same helper the fp8/mxfp8
amax paths already use), and resolve the launch stream BEFORE _thd_pack in
both SM120 callers. Allocations happen inside the context too, so
caching-allocator blocks are stream-tagged to the stream that uses them.

Pre-existing since the FROST engines landed (NVIDIA#476); split out of the NVIDIA#526
review round to keep that PR scoped to native THD stride support. Only
direct graph-API users with an explicit handle stream are affected — the
PyTorch integration launches on torch's current stream.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
vedaanta added a commit to vedaanta/cudnn-frontend that referenced this pull request Aug 13, 2026
…tor scratch (SM100)

A per-execute fill kernel on the THD execute hot path initialized the
per-sequence O TMA-descriptor buffer, whose contents provably do not
matter: the kernel's builder pass copies every qword of each sequence's
slot from the base descriptor (then patches address/extent) before the
fence and before any consumer read — stale workspace bytes never survive
to a read. The +16-qword tail is never read at all.

The fill dates to the original FROST landing (NVIDIA#476) as belt-and-braces.
Rule 1: no adapter-side fills on the execute hot path.

(The matching dummy-sinks fill removal is split into its own PR.)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
vedaanta added a commit to vedaanta/cudnn-frontend that referenced this pull request Aug 15, 2026
The THD execute paths do torch host work before the kernel launch — the
[seq_kv | cu_q | cu_k] metadata allocation + D2H length reads + one-shot
H2D upload (SM100 and the shared SM120 _thd_pack), the per-sequence
O-descriptor buffer (SM100), the dummy-sink buffer (SM100), and the cached
seq_q dummy's first-use allocation (SM120). These enqueued on torch's
CURRENT stream while the kernel launches on the stream carried by the
execute-time handle (ExecutionContext.stream): when the two differ, the
prep and the kernel race.

Run the prep inside _torch_stream_context (the same helper the fp8/mxfp8
amax paths already use), and resolve the launch stream BEFORE _thd_pack in
both SM120 callers. Allocations happen inside the context too, so
caching-allocator blocks are stream-tagged to the stream that uses them.

Pre-existing since the FROST engines landed (NVIDIA#476); split out of the NVIDIA#526
review round to keep that PR scoped to native THD stride support. Only
direct graph-API users with an explicit handle stream are affected — the
PyTorch integration launches on torch's current stream.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
vedaanta added a commit to vedaanta/cudnn-frontend that referenced this pull request Aug 15, 2026
…tor scratch (SM100)

A per-execute fill kernel on the THD execute hot path initialized the
per-sequence O TMA-descriptor buffer, whose contents provably do not
matter: the kernel's builder pass copies every qword of each sequence's
slot from the base descriptor (then patches address/extent) before the
fence and before any consumer read — stale workspace bytes never survive
to a read. The +16-qword tail is never read at all.

The fill dates to the original FROST landing (NVIDIA#476) as belt-and-braces.
Rule 1: no adapter-side fills on the execute hot path.

(The matching dummy-sinks fill removal is split into its own PR.)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
vedaanta added a commit that referenced this pull request Aug 15, 2026
…THD compile keys (#552) (#543)

* frost(sdpa): bind the THD host prep to the launch stream

The THD execute paths do torch host work before the kernel launch — the
[seq_kv | cu_q | cu_k] metadata allocation + D2H length reads + one-shot
H2D upload (SM100 and the shared SM120 _thd_pack), the per-sequence
O-descriptor buffer (SM100), the dummy-sink buffer (SM100), and the cached
seq_q dummy's first-use allocation (SM120). These enqueued on torch's
CURRENT stream while the kernel launches on the stream carried by the
execute-time handle (ExecutionContext.stream): when the two differ, the
prep and the kernel race.

Run the prep inside _torch_stream_context (the same helper the fp8/mxfp8
amax paths already use), and resolve the launch stream BEFORE _thd_pack in
both SM120 callers. Allocations happen inside the context too, so
caching-allocator blocks are stream-tagged to the stream that uses them.

Pre-existing since the FROST engines landed (#476); split out of the #526
review round to keep that PR scoped to native THD stride support. Only
direct graph-API users with an explicit handle stream are affected — the
PyTorch integration launches on torch's current stream.

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

* frost(sdpa): drop the redundant zero-fill of the never-read O-descriptor scratch (SM100)

A per-execute fill kernel on the THD execute hot path initialized the
per-sequence O TMA-descriptor buffer, whose contents provably do not
matter: the kernel's builder pass copies every qword of each sequence's
slot from the base descriptor (then patches address/extent) before the
fence and before any consumer read — stale workspace bytes never survive
to a read. The +16-qword tail is never read at all.

The fill dates to the original FROST landing (#476) as belt-and-braces.
Rule 1: no adapter-side fills on the execute hot path.

(The matching dummy-sinks fill removal is split into its own PR.)

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

* frost(sdpa): compile THD with dynamic token extents — plan-time-only compile keys

The THD execute paths keyed the per-shape kernel compile on the packed
token totals (sq=t_q, skv=t_kv, and max_sq on SM120). Under continuous
batching the totals change every step, so the lru_cache degenerated into
a fresh multi-second cute.compile per execute (issue #552's worst leg).

- Kernel modules (SM100 d128/d192_d128/d256/d512 f16, SM120 f16/fp8):
  under THD the fake tensors' token extents are cute.sym_int symbols
  (one per ragged group — Q/O/LSE share t_q, K/V share t_kv) and the
  batch stride is rebuilt symbolically (the real view's batch stride is
  t * token_stride, a runtime value that never steps at batch extent 1).
  sq/skv are ignored under THD; SM100's _host reads the runtime totals
  from the dynamic tensor shapes. SM120's max_sq moves from a compile
  parameter to a runtime __call__ argument that sizes the per-sequence
  grid; trace-time shape checks compare only statically-known modes.
- Adapter: the THD compile key is now derivable from the graph
  declaration alone, so compile() builds the artifact at PLAN time (the
  "thd-deferred" sentinel remains only for the unwired SM100 fp8 THD)
  and the execute paths' lru-cached compile calls are guaranteed hits;
  a shared _thd_compile_kwargs() keeps the two call sites identical.
  The all-KV-zero clamp's swapped K/V strides mint their own entry.
- The D2H .tolist() round-trip still feeds the metadata upload, the
  ragged views' extents and the exact grid — removing it (and the CUDA-
  graph capture blocker) needs the plan-time-max grid + device
  cu_seqlens redesign tracked in #552.
- New regression tests (SM100 + SM120) prove one compiled artifact
  serves different packed totals, checking numerics per total and
  asserting zero cache misses across executes.

Verified on SM100 (B200-class): 487 passed / 4 skipped across the f16
dense+THD flavors, fp8, mxfp8, graph-level THD and sdpa op suites.

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

* docs(frost): AGENTS.md Hard Rules 4 (plan-time-only compile keys) and 5 (launch-stream-ordered execute)

Renumbered after #570 landed Rule 3 (no D2H reads on execute); these two
complement it.

Rule 4 codifies issue #552's compile-key lesson: never key a kernel
compile on runtime data values — runtime extents compile dynamic
(cute.sym_int), runtime launch scalars are call arguments, derived values
(batch strides computed from totals) count as leaks, and with a
plan-time-only key the compile belongs at plan time with a cache-miss
regression test guarding the execute path. Rule 3 bans the read that
feeds such a key; Rule 4 bans the key itself. The SM80 _compile_cached
(#493) is flagged as the known open cleanup.

Rule 3's THD known-violation entry is updated: the compile-side half is
done (dynamic token extents), so t_q/t_kv now reach the host only for the
metadata upload, ragged view extents and the launch grid.

Rule 5 codifies this PR's stream-binding fix: every torch operation on
the execute path (H2D uploads, buffer resets, allocator calls,
post-kernel consumers) is ordered on the launch stream via
_torch_stream_context, never implicitly on torch's current stream.

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. orig-nv-eng Reported or requested by NVIDIA engineering.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants