sdpa: require FP32 Stats and default an unset Stats dtype to FP32 - #690
Conversation
The SDPA kernels always compute and store Stats (logsumexp) as FP32, 4 bytes per row. A graph that declared Stats with a narrower dtype -- explicitly, or implicitly by leaving it unset with a non-FP32 io_data_type (fill_from_context assigned the io dtype) -- built and executed fine, and the kernel then wrote FP32 rows past the end of the buffer the caller sized from the declared dtype: silent corruption of adjacent allocations, illegal memory accesses, or kernel launch failures, depending on what the stray writes hit. - Graph::sdpa_internal sets the Stats output dtype to FLOAT at creation, so no later fill can assign the io dtype. - SDPANodeBase::infer_properties_node defaults a still-unset Stats dtype to FLOAT (direct node-construction paths). - SDPANodeBase::post_validate_node rejects an explicitly non-FP32 Stats with GRAPH_NOT_SUPPORTED instead of corrupting memory at execute. - The python IR layer (nodes.py) applies the same FP32 default for SDPA/SDPA_FP8/SDPA_MXFP8 Stats before its generic io-dtype fill. Root-caused from a customer workload where an fp16 Stats buffer half the required size was overwritten by batch >= 1 stats rows, corrupting whichever allocation happened to be adjacent. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Enterprise Run ID: 📒 Files selected for processing (4)
Included review availability: Your plan provides up to 12 included reviews per hour; 11 remain after this review. 📝 WalkthroughWalkthroughSDPA Stats outputs now use FP32 when generated or inferred. Validation rejects explicitly declared non-FP32 Stats types. Python regression tests cover invalid, inferred, and explicit FP32 cases. ChangesSDPA Stats dtype handling
Estimated code review effort: 2 (Simple) | ~10 minutes Merge Risk: ⚪ Minimal · up to The PR prevents undersized SDPA Stats buffers by defaulting Stats to FP32 and rejecting incompatible declarations; no actionable merge-blocking risk remains beyond normal checks and review. Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
|
@cudnn-ci-bot run frost |
|
🏁 Pipeline finished SHA: |
The SDPA Stats output must be FP32 since #690; the low-level API sample was allocating and declaring it as BF16, failing the py_samples CI job. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Problem
The SDPA kernels always compute and store Stats (logsumexp) as FP32, 4 bytes per row. A graph that declared Stats with a narrower dtype — explicitly, or implicitly by leaving it unset with a non-FP32
io_data_type(fill_from_contextassigned the io dtype) — built and executed fine, and the kernel then wrote FP32 rows past the end of the buffer the caller sized from the declared dtype. Depending on what the stray writes hit, this surfaced as silent corruption of adjacent allocations, illegal memory accesses, orCUDNN_STATUS_EXECUTION_FAILED_CUDA_DRIVERlaunch failures.Root-caused from a customer workload: an fp16 Stats buffer (half the required bytes) was overwritten by batch ≥ 1 stats rows, corrupting whichever allocation happened to be adjacent — verified with compute-sanitizer (invalid f32 global writes starting exactly at byte offset
batch_idx * s_q * 4, one byte past the fp16-sized allocation).Fix
Graph::sdpa_internalsets the Stats output dtype to FLOAT at creation, so no later fill can assign the io dtype.SDPANodeBase::infer_properties_nodedefaults a still-unset Stats dtype to FLOAT (covers direct node-construction paths).SDPANodeBase::post_validate_noderejects an explicitly non-FP32 Stats withGRAPH_NOT_SUPPORTED("The Stats output of sdpa must be an FP32 tensor.") instead of corrupting memory at execute.nodes.py) applies the same FP32 default for SDPA / SDPA_FP8 / SDPA_MXFP8 Stats before its generic io-dtype fill.Testing
test/python/test_sdpa_stats_fp32_required.py: explicit fp16/bf16 Stats rejected atvalidate()(per io dtype), unset Stats inferred FP32, FP32 Stats accepted — 7/7 pass on B200 + cuDNN 9.26.0.33.graph.validate()harness: FLOAT OK, HALF rejected, unset inferred FLOAT.test_sdpa_fp32_rejected.py,test_sdpa_with_caching.py,test_sdpa_custom_features.py— 23/23 pass (including native-engine paths).🤖 Generated with Claude Code
Summary by CodeRabbit
Bug Fixes
Tests