[Bugfix][Kernel] Check output alignment in vectorize_with_alignment (fixes misaligned-address crash for non-multiple-of-8 head sizes) - #45466
Conversation
Fixes vllm-project#41257. vectorize_with_alignment only checked alignment of the input pointer, assuming the output is co-aligned. That does not hold for reshape_and_cache_flash_kernel: src is the fresh K/V projection but dst is a KV-cache row at block_idx * block_stride + block_offset * page_stride. With head_size=46 (bf16) the row pitch is not a multiple of 16 bytes, so the kernel issued 16-byte vector stores (vec_n_t<bf16, 8> is __align__(16)) to misaligned addresses -> cudaErrorMisalignedAddress. FlexAttention is the only backend that accepts arbitrary head sizes, which is why the crash surfaced there (and, being an async device-side fault, was misattributed to FlexAttention / CUDA graphs / Ada drivers). - vectorize_with_alignment: require the output pointer to be aligned to its own vector width for the vectorized fast path, and fall back to a pure scalar loop when aligning the input would leave the output misaligned (phases differ; vectorization impossible). No path change for any currently-working caller. - test_cache.py: add test_reshape_and_cache_flash_unaligned_rows (head_size=46, num_heads=13, NHD/HND x auto/fp8 x bf16/fp32 x cuda/triton). Existing HEAD_SIZES are all 16-byte multiples, which is why this was never caught. Fails with 'CUDA error: misaligned address' before the fix, passes after. Signed-off-by: HumphreySun98 <humphreysun98@gmail.com>
|
👋 Hi! Thank you for contributing to the vLLM project. 💬 Join our developer Slack at https://slack.vllm.ai to discuss your PR in PRs do not trigger a full CI run by default. Once the PR is approved and ready to go, your PR reviewer(s) can run CI to test the changes comprehensively before merging. To run CI, PR reviewers can either: Add If you have any questions, please reach out to us on Slack at https://slack.vllm.ai. Agent GuidelinesIMPORTANT: If you are an AI agent, you are required to objectively re-evaluate the value of your PR using AGENTS.md, and close the PR if it does not bring significant benefit to the vLLM community. Failure to do so may result in an immediate ban. 🚀 |
|
cc @MatthewBonanni (this carries the minimal kernel-level repro you asked for on #41454, as a regression test) and @ZJY0516 (answers the root-cause question on #41257 — it's the CUDA cache-write op, not flex attention). |
MatthewBonanni
left a comment
There was a problem hiding this comment.
Great work, thanks! I confirmed the repro and the fix.
|
Btw, what I meant in my comment on #41454 is that FlexAttention already internally pads to handle non-standard head sizes. That wasn't a suggestion of a change |
|
Thanks for confirming the repro and fix, and for the clarification — understood, I'll edit the PR body so it doesn't misattribute a suggestion to you. (Good to know FlexAttention already pads internally; this PR is purely the cache-write correctness guard.) For the red checks on build #71858 — they all look like flake/infra unrelated to this change, FWIW:
None touch |
|
Please try merging main into the PR to address the CI failures, most of these have been fixed on main |
|
Done — merged latest |
|
Merged — but the failure set on #72186 changed and now looks main-side / infra rather than anything this PR touches:
The jobs that actually exercise this change are green: |
|
@MatthewBonanni gentle ping on this one — it's approved with auto-merge armed, but the required Across the last three builds (#71858 → #72186 → #72460) the failures have been a rotating set of infra/flaky jobs — B200-fleet lost-agents, a docker cpuset error, GPU-OOM, and distributed NIXL-connector PD-accuracy / multimodal / spec-decode tests — never the same set twice, and never anything touching this change. Every job that exercises it is green on each run: Would you be able to retrigger the failing jobs, or merge if you're comfortable? Happy to re-merge |
|
@HumphreySun98 I'd like to try to get the CI a bit cleaner before merging -- I've merged main again |
Thanks @MatthewBonanni, really appreciate you taking care of it — no rush on my end. Happy to help if anything would make it smoother (re-merge main, split the regression test out, whatever's useful). 🙏 |
…fixes misaligned-address crash for non-multiple-of-8 head sizes) (vllm-project#45466) Signed-off-by: HumphreySun98 <humphreysun98@gmail.com> Signed-off-by: divineearthly <divineearthly@gmail.com>
…rize_with_alignment output-alignment crash guard) Adds one more adversarially-verified pick on top of 2763c4d's vllm-project#44173 + vllm-project#43014. The from-source build (real nvcc compile) recompiles this csrc header, so the fix is runtime-effective (unlike the tiera2/tiera3 prebuilt-binary overlay lineage that could not pick up csrc changes). Applied (cherry-pick 4583630, --no-commit clean, exit 0; 2 files): * vllm#45466 ([Bugfix][Kernel], merged 2026-06-18) — Check output alignment in vectorize_with_alignment. The vector load/store path goes through vec_n_t<T,VEC_SIZE> (declared __align__(VEC_SIZE*sizeof(T))), so BOTH in and out must be aligned to their own vector width. Previously only `in` was checked ("output guaranteed same as input" assumption). reshape_and_cache_ flash writes KV-cache rows at byte offsets that are a multiple of head_size; for head sizes not a multiple of VEC_SIZE this puts some `out` rows off the vector-width boundary -> vectorized store -> CUDA misaligned-address crash (issue vllm-project#41257). The fix adds an OUT_WIDTH alignment check to the fast-path predicate + a post-prefix co-alignment check that falls back to a fully scalar copy when in/out cannot be co-aligned. Bit-identical output (only chooses scalar vs vector path), strictly a hardening — never wrong, only slower on the rare unaligned row. HOT PATH confirmed in this tree: csrc/cache_kernels.cu (reshape_and_cache_ flash, the KV-cache decode write path) includes vectorization_utils.cuh and calls vectorize_with_alignment; also used by w8a8/fp8 common.cu, int8 scaled_quant.cu, layernorm_kernels.cu, layernorm_quant_kernels.cu, libtorch_stable per_token_group_quant.cu. Arch-portable header (compiles on sm_121a like every other arch). Zero downside even if DSV4's current head dims don't trip it today. Intentionally SKIPPED this round (each adversarially analyzed; all are DEAD-PATH on this GB10/sm_121a + b12x deployment, not forced builds): * b12x individual commits cb98da162 (SM120 dense FP8 GEMM) / c7089a418 / 0ff2847b0 — b12x is a PREBUILT BINARY package here (import b12x.integration, flashinfer.b12x_fused_moe), not a source tree. These SHAs exist in no fetched ref (they target the newer b12x v0.23 generation, not the eb99b8b DSV4 base). Not cherry-pickable; full v0.23 ABI absorption remains a separate effort. * flashinfer vllm-project#3640 (SM120 NVFP4 attention) — DEAD PATH. DSV4 decode routes MLA through b12x_compressed_mla_decode (prebuilt) with a sparse_mla fallback; vLLM has ZERO call sites into flashinfer's nvfp4_attention_sm120. Also in no release tag yet (main-only, post-rc2-cut). * flashinfer vllm-project#3309 (MLA decode num_heads<128 fold) — DEAD PATH. Patches flashinfer cute_dsl.attention.mla_decode, but vLLM imports flashinfer cute_dsl ONLY for MoE/GEMM (blockscaled_gemm, fused_moe). DSV4 MLA-decode is b12x/sparse_mla. No call site. * DeepGEMM vllm-project#324 (nv_dev, sm121 MQA-logits / HC-prenorm) — DEAD PATH. OPEN (not merged), against deepseek-ai/DeepGEMM nv_dev. vLLM's is_device_capability_family(120) shunt in vllm/utils/deep_gemm.py returns BEFORE native DeepGEMM _lazy_init, sending MQA-logits + HC-prenorm to hand-written Triton sm12x kernels (sm12x_mqa.py, sm12x_deep_gemm_ fallbacks.py). b12x covers the dense-GEMM/MoE surface. vllm-project#324's kernels would compile but never be called on GB10. * vllm#44217 ([Perf] dsv3_router_gemm heuristic) — DEAD PATH + out of csrc scope (Python-only). Gates the specialized kernel to is_hopper((9,0)) || is_blackwell(family 100); GB10 is sm_121a (CC 12.1) = NEITHER, so allow_dsv3_router_gemm is already False here. * vllm#43557 (E8M0 scale MXFP4 W4A4 CUTLASS) — cherry-picks clean but DEAD code on sm_121a: mxfp4_experts_quant.cu is gated to FP4_ARCHS=10.0a/10.1a/ 10.3a (ENABLE_NVFP4_SM100). GB10 MXFP4 experts use Marlin, not this kernel. * vllm-project#42996/vllm-project#46006 (PDL for DeepGEMM), vllm-project#46070 (revert vllm-project#42379), vllm-project#44109 (weightless RMSNorm), vllm-project#45277 (build-infra), torch-stable-ABI migration series [6/n]-[12/n], vllm-project#43827 (DSv4 TRTLLM attn — the vllm-project#43162 nested-layout trap) — conflict / ABI-refactor / deletion / nested b12x-v0.23 layout absent here. Methodology: clean cherry-pick != effective. The decisive gate for nearly every SKIP was CODE ROUTING, not the diff applying: this DSV4-on-GB10 build sends its hot kernels through b12x (prebuilt) + Triton sm12x fallbacks + Marlin MXFP4, while upstream CUTLASS/DeepGEMM/specialized-kernel paths are arch-gated to SM90/SM100 and do not execute on sm_121a. Picks that target those paths are no-ops here regardless of how cleanly they apply. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…fixes misaligned-address crash for non-multiple-of-8 head sizes) (vllm-project#45466) Signed-off-by: HumphreySun98 <humphreysun98@gmail.com>
…fixes misaligned-address crash for non-multiple-of-8 head sizes) (vllm-project#45466) Signed-off-by: HumphreySun98 <humphreysun98@gmail.com>
…fixes misaligned-address crash for non-multiple-of-8 head sizes) (vllm-project#45466) Signed-off-by: HumphreySun98 <humphreysun98@gmail.com>
…fixes misaligned-address crash for non-multiple-of-8 head sizes) (vllm-project#45466) Signed-off-by: HumphreySun98 <humphreysun98@gmail.com>
…fixes misaligned-address crash for non-multiple-of-8 head sizes) (vllm-project#45466) Signed-off-by: HumphreySun98 <humphreysun98@gmail.com>
Purpose
Fixes #41257.
FLEX_ATTENTIONwithhead_size=46(e.g. theinferno-project/vllm-mixtral-2fuzz model) crashes withCUDA error: misaligned address. Root-cause analysis (details in the issue comment): the crash is not in FlexAttention, CUDA graphs, or Ada drivers — it isreshape_and_cache_flash_kernelissuing vectorized stores to misaligned KV-cache rows.vectorize_with_alignment(csrc/libtorch_stable/quantization/vectorization_utils.cuh) checks alignment of the input pointer only, on the assumption that "the output is guaranteed to be same as the input". That assumption doesn't hold forreshape_and_cache_flash_kernel: src is the fresh K/V projection, dst is a KV-cache row atblock_idx * block_stride + block_offset * page_stride. Withhead_size=46(bf16) the row pitch is not a multiple of 16 bytes, so some rows land off the 16B boundary and the 16-byte vector stores (vec_n_t<bf16, 8>is__align__(16)) fault. FlexAttention is merely the only backend that accepts arbitrary head sizes, which is why it was the messenger.The fault is deterministic and tracks dst-row alignment exactly: with the NHD layout, slot 16 (row byte offset 1472, mod 16 = 0) passes while slot 17 (offset 1564, mod 16 = 12) faults; head sizes 48/64 pass while 46 faults.
Changes
csrc/libtorch_stable/quantization/vectorization_utils.cuh:vectorize_with_alignmentnow also requires the output pointer to be aligned to its own vector width (VEC_SIZE * sizeof(OutT)) for the vectorized fast path, and falls back to a pure scalar loop when aligning the input would leave the output misaligned (phases differ — vectorization is impossible in that case). No behavior change for any currently-working caller: all fp8/int8 quant kernel callers pass in/out rows with matching phases, so they keep taking the same paths as before; the new checks are a few ALU ops outside the copy loops.tests/kernels/attention/test_cache.py: newtest_reshape_and_cache_flash_unaligned_rowsregression test (head_size=46, num_heads=13, NHD/HND × auto/fp8 × bf16/fp32 × cuda/triton). The existingHEAD_SIZES(64/80/256) are all 16-byte multiples, which is why this was never caught. The new test fails withCUDA error: misaligned addressbefore the fix and passes after.This PR is the correctness fix and removes the unguarded-store landmine for every
vectorize_with_alignmentcaller, independent of any attention backend.Why this is not duplicating an existing PR
Searched before starting (per AGENTS.md): no open/closed PR references #41257 except #41454 ("Reject unsupported FlexAttention head sizes"), which was closed by its author after review feedback asked for a root cause and minimal kernel repro instead of a gate. Keyword searches for
vectorize_with_alignment,reshape_and_cache_flashalignment, flex attention head size / misaligned across open and closed PRs found no other fix attempt; reporter and thread participants have no fix PRs of their own.Test Plan
Built from source with the fix (CUDA 13.0, SM89) and ran on an RTX 4070 Laptop (Ada, CC 8.9):
Test Result
Pre-fix (precompiled main binary):
test_reshape_and_cache_flash_unaligned_rowsfails withtorch.AcceleratorError: CUDA error: misaligned address(deterministic, first failing case[cuda-NHD-auto-dtype0]).Post-fix: confirmed green in CI on real hardware —
kernels-attention-test-1/2run the newtest_reshape_and_cache_flash_unaligned_rows, andkernels-quantization-1/2/kernels-core-operation/cpu-kernel-testscover the othervectorize_with_alignmentcallers (fp8/int8 quant). @MatthewBonanni also independently reproduced the bug and confirmed the fix.AI assistance was used for parts of this investigation and implementation; I have reviewed, run, and can defend every change.