Skip to content

[Bugfix][Triton] Fix int32 KV-offset overflow in _mla_gluon >2GB path - #4474

Merged
valarLip merged 1 commit into
ROCm:mainfrom
peizhang56:fix_k3_prefix_cache_spec_decode
Aug 4, 2026
Merged

valarLip merged 1 commit into
ROCm:mainfrom
peizhang56:fix_k3_prefix_cache_spec_decode

Conversation

@peizhang56

Copy link
Copy Markdown
Contributor

On the WITHIN_2GB=False path the KV offset kv_loc * stride_kv_c_bs is computed in int32 and overflows (that overflow is precisely why this branch exists), yielding a wild 64-bit pointer in the global_load fallback and a SIGSEGV in _mla_gluon.

Promote stride_kv_c_bs and stride_k_pe_bs to int64 when not WITHIN_2GB so the whole offset computes in 64-bit. The buffer_load path (WITHIN_2GB=True) keeps 32-bit offsets by hardware requirement; the guard is constexpr so it folds out there.

Motivation

_mla_gluon crashes with a SIGSEGV when the KV cache exceeds 2GB. In that case the kernel selects the WITHIN_2GB=False code path, but the KV offset kv_loc * stride_kv_c_bs is still computed in int32. For a >2GB cache this multiplication overflows, and the overflowed offset is added to the 64-bit base pointer in the global_load fallback, producing an out-of-bounds pointer and a segfault. The overflow is precisely the condition that selects this branch, so the offset must be computed in 64-bit.

Technical Details

Promote stride_kv_c_bs and stride_k_pe_bs to gl.int64 when not WITHIN_2GB, so every downstream offset computation (kv_loc * stride_kv_c_bs + ... for the KV cache, and the corresponding stride_k_pe_bs expressions for K_pe) is evaluated in 64-bit and no longer overflows. The reassignment happens before the first offset is built, so all load sites pick up the widened strides. The buffer_load path (WITHIN_2GB=True) intentionally keeps 32-bit offsets, which is a hardware requirement of buffer_load_to_shared; since WITHIN_2GB is a gl.constexpr, the guard folds out entirely on that path and there is no runtime or performance impact.

Test Plan

Ran the MLA gluon kernel with a KV cache sized above 2GB to force the WITHIN_2GB=False / global_load path, and confirmed the same configuration crashed before the change. Also exercised the WITHIN_2GB=True path to confirm no behavioral or performance change (the guard folds out at compile time).

Test Result

Before: SIGSEGV in _mla_gluon on the >2GB KV-cache configuration. After: the kernel runs correctly and produces expected output; the WITHIN_2GB=True path is unchanged. No new unit test is added because reproducing this reliably requires allocating a >2GB KV cache, which is impractical in the standard op_test harness.

Submission Checklist

@peizhang56
peizhang56 requested a review from a team July 31, 2026 02:57
@github-actions

Copy link
Copy Markdown
Contributor

🏷️ CI Guide

Runs automatically on every PR:

  • ✅ Pre-checks (submodule verification, code formatting)
  • ✅ Aiter op tests (gfx942 + gfx950)
  • ✅ Triton tests on MI35X (only when aiter/ops/triton/** or related paths are changed)

Extended tests (opt-in via labels):

Label Tests
ci:triton-300x Run an additional Triton test job on MI300X in PRs; main branch always runs both MI35X and MI300X
ci:sglang SGLang integration tests: DeepSeek-R1-MXFP4 accuracy, Qwen 3.5 accuracy
ci:atom ATOM benchmark: DeepSeek-R1-0528, GPT-OSS-120B
ci:atom_full ATOM accuracy suite for PR and main models from ATOM models_accuracy.json
ci:vllm vLLM benchmark: GPT-OSS-120B, DeepSeek-R1-0528, Kimi-K2.5
ci:all All standard extended tests (excludes ci:atom_full)

Only add ci:atom_full for FlyDSL or Triton upgrades.
Add labels via the sidebar or gh pr edit 4474 --add-label <label>

dllehr-amd
dllehr-amd previously approved these changes Jul 31, 2026

@dllehr-amd dllehr-amd left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks @peizhang56 ! Looks good on my side!

On the WITHIN_2GB=False path the KV offset kv_loc * stride_kv_c_bs is
computed in int32 and overflows (that overflow is precisely why this
branch exists), yielding a wild 64-bit pointer in the global_load
fallback and a SIGSEGV in _mla_gluon.

Promote stride_kv_c_bs and stride_k_pe_bs to int64 when not WITHIN_2GB so
the whole offset computes in 64-bit. The buffer_load path (WITHIN_2GB=True)
keeps 32-bit offsets by hardware requirement; the guard is constexpr so it
folds out there.

Signed-off-by: pei.zhang <pei.zhang@amd.com>
@peizhang56
peizhang56 force-pushed the fix_k3_prefix_cache_spec_decode branch from 95e6195 to 1e4135b Compare July 31, 2026 21:40
JohnQin-llm added a commit to JohnQin-llm/aiter-amd that referenced this pull request Aug 2, 2026
KV addresses are built as kv_loc * stride_kv_c_bs + offs_d with both operands
int32, so for a 576-wide bf16 row the product wraps once a page id passes
2**31 // 576 = 3,728,270 and the load lands below the cache base:

    Memory access fault by GPU node-N ... Reason: Unknown

The existing cases in test_mla.py already compile and run the WITHIN_2GB=False
branch -- kv_max_sz = 65536*32 = 2,097,152 rows is 2.25 GiB, over the 2 GB
cutoff -- but page ids top out at 2,097,151, a factor of 1.78 below the wrap
point, so the branch cannot trigger the overflow. --sequential_page_indices,
which is commented "byte offset can exceed 2^32", reaches ~2,107,152 rows at
batch 256 x ctx 8192 and is still 1.77x short.

Add a case with a 4.72 GiB cache (4,400,000 rows) indexed at row 4,255,488,
covering both a BLOCK_N-aligned length and a partial trailing tile.

The launch runs in a subprocess: a GPU memory fault aborts the interpreter
rather than raising, so an in-process test would SIGABRT and take out the
remaining files in the CI shard instead of reporting one failure. Verified in
both directions on 8x MI355X -- with the fix the child exits 0, on unfixed main
the child exits -6 and the parent reports a clean AssertionError and continues.

Gated on gfx950 and on torch.cuda.mem_get_info() with a 1.3x margin, following
the convention in test_batch_prefill.py.

Depends on ROCm#4474: this test fails on main until that fix merges.

Signed-off-by: Yanyuan Qin <yanyuan.qin@amd.com>
@peizhang56
peizhang56 requested a review from valarLip August 2, 2026 03:32
@peizhang56

Copy link
Copy Markdown
Contributor Author

Hi @valarLip will you be able to help to review this code change.
There was a vllm k3 coredump due to interger overflow from K3 when prefix cache + triton_mla + dspark spec decode enabled.
I believe different ppl have tested with this, which fixed the coredump for vllm.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants