Skip to content

rocm: bound the INT8 lm_head GEMV dispatch by the kernel's max N - #1240

Open
zohaibm-amd wants to merge 1 commit into
gfx11from
zohaibm.int8-lm-head-n-guard
Open

rocm: bound the INT8 lm_head GEMV dispatch by the kernel's max N#1240
zohaibm-amd wants to merge 1 commit into
gfx11from
zohaibm.int8-lm-head-n-guard

Conversation

@zohaibm-amd

@zohaibm-amd zohaibm-amd commented Aug 24, 2026

Copy link
Copy Markdown

Summary

--dynamic-lm-head-quantization int8 (and int8:gN) kills the EngineCore process once the scheduler batches enough concurrent decode requests.

hip_w8a16.py routes the lm_head GEMV to wvSplitK_int8 whenever the activation tile fits in LDS, admitting any batch N up to floor(32768 / K). The kernel's switch in csrc/rocm/skinny_gemms_w8a8.cu implements N of 1 through 5 and throws on the default branch.

Fix. Require N to be within what the kernel implements as well as fitting in LDS.

Test plan

  • N_BATCH in test_dynamic_int8_lm_head.py gains 5 and 6 — the last N the kernel implements and the first that must fall back. It previously stopped at 4, which is why the gap went unnoticed.

Duplicate check

No open PR touches hip_w8a16.py or skinny_gemms_w8a8.cu. Neither file exists upstream in vllm-project/vllm--dynamic-lm-head-quantization is a fork-specific feature (#888) — so no upstream PR can be duplicating it, and there is nothing upstream to cherry-pick.

AI assistance

AI assistance (Claude Code) was used to locate the dispatch/kernel mismatch and prepare this change. The crash was reproduced and its traceback observed directly; the N bound was read from the kernel's switch statement rather than assumed.

The dispatch in hip_w8a16.py routed the lm_head GEMV to wvSplitK_int8
whenever the activation tile fit in LDS, admitting any batch N up to
floor(32768 / K). The kernel's switch in csrc/rocm/skinny_gemms_w8a8.cu
only implements N of 1 through 5 and throws on the default branch, so
any K with floor(32768 / K) of 6 or more handed it a batch it cannot
service:

  RuntimeError: Unsupported N value: 262144,5376,6

The throw does not unwind cleanly through _prefer_hipblaslt_for_logits,
so it killed the whole EngineCore process rather than failing one
request. Observed serving a 31B AWQ model with
--dynamic-lm-head-quantization int8 as soon as six decode requests were
scheduled together; identical with int8:g32.

Smaller hidden sizes are more exposed, since the window is every N from
6 up to floor(32768 / K): 6 only at K=5376, but 6-16 at K=2048.

Require N to be within what the kernel implements as well as fitting in
LDS. Larger batches fall back to F.linear on the retained unquantized
weights, which is already the designed path above the LDS bound, so the
fallback is correctness-preserving and marginally more accurate than the
INT8 path it replaces.

The dispatch bound was introduced by 7847fce, which replaced a prior
AssertionError with the LDS-capacity check without cross-checking it
against the kernel's N switch.

Changes:
- N_BATCH in the existing test gains 5 and 6: the last N the kernel
  implements and the first that must fall back. It previously stopped at
  4, which is why the gap went unnoticed. All three MK_SHAPES reach the
  kernel at N=6, so every one of them reproduces the throw without this
  fix.

Signed-off-by: Zohaib Moti <zohaib.moti@amd.com>

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@zohaibm-amd
zohaibm-amd marked this pull request as ready for review August 26, 2026 16:44
@zohaibm-amd
zohaibm-amd requested a review from eble-amd August 31, 2026 17:14

@eble-amd eble-amd left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

OK, but it would be nice to understand why support currently ends at 5. What if the ideal solution to this problem involves not just respecting the kernel's limitations in this layer, but also extending the kernel's capabilities?

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.

2 participants