Skip to content

[CPU] Restore linear dispatch for small unquantized GEMMs - #51379

Merged
bigPYJ1151 merged 2 commits into
vllm-project:mainfrom
bigPYJ1151:cpu-restore-sgl-small-gemm-dispatch
Aug 10, 2026
Merged

bigPYJ1151 merged 2 commits into
vllm-project:mainfrom
bigPYJ1151:cpu-restore-sgl-small-gemm-dispatch

Conversation

@bigPYJ1151

@bigPYJ1151 bigPYJ1151 commented Aug 7, 2026

Copy link
Copy Markdown
Member

Purpose

PR #50801 removed the SGLang AMX weight_packed_linear path from the CPU
unquantized (bf16/fp16) linear dispatch, leaving oneDNN's onednn_mm as the
only kernel for that path. For small weights -- most notably MoE router/gate
projections, where N is the expert count rather than a hidden-size-scaled
dimension -- oneDNN never reaches its compute-bound regime regardless of
batch size, so the SGL kernel's lower per-call dispatch overhead wins across
the full measured M range. This restores that dispatch for weights small
enough to benefit, while leaving larger dense projections (qkv/o_proj/
gate_up/down/lm_head) on oneDNN.

Changes

  • check_cpu_sgl_kernel: restore dispatch to the SGL AMX kernel for bf16/fp16
    unquantized GEMMs, gated by a _CPU_SGL_GEMM_MAX_WEIGHT_BYTES (1 MiB)
    weight-size threshold so it only applies to small weights (comfortably
    covers MoE router/gate weights while staying below dense projections).
    This threshold does not affect the existing int8 scaled_mm path, which is
    a separate consumer of the same function.
  • Add a runtime AMX-FP16 capability check (torch.cpu._is_amx_fp16_supported)
    for the fp16 branch. AMX-BF16/INT8 (amx_tile) and AMX-FP16 are separate
    CPU ISA extensions -- e.g. Sapphire/Emerald Rapids expose the former but
    not the latter -- and SGL's can_use_brgemm<at::Half> always attempts
    brgemm for fp16 regardless of M, so fp16 needs its own capability gate
    rather than piggybacking on amx_tile.

Test Plan

Correctness (offline inference, dispatch path confirmed via debug logs):

python3 examples/basic/offline_inference/generate.py --dtype=bfloat16 --model=Qwen/Qwen2.5-0.5B-Instruct
python3 examples/basic/offline_inference/generate.py --dtype=bfloat16 --model=ibm-granite/granite-4.0-h-tiny
python3 examples/basic/offline_inference/generate.py --model=openai/gpt-oss-20b

End-to-end serving benchmark on the one locally-cached model with a genuinely
unquantized (fp16) router gate, Qwen/Qwen3-30B-A3B-GPTQ-Int4:

vllm serve Qwen/Qwen3-30B-A3B-GPTQ-Int4 --no-enable-prefix-caching --port 8000
vllm bench serve --backend vllm --model Qwen/Qwen3-30B-A3B-GPTQ-Int4 \
  --dataset-name random --num-prompts 32 --random-input-len 1024 \
  --random-output-len 256 --request-rate inf --num-warmups 32 \
  --temperature 0 --ignore-eos

Test Result

Correctness: all three models produced coherent generations, with debug logs
confirming the expected dispatch on each linear:

  • Qwen2.5-0.5B-Instruct (dense, bf16): all linears route to oneDNN (weights
    above the 1 MiB threshold), unchanged from before this PR.
  • granite-4.0-h-tiny (hybrid mamba/attention MoE, bf16): router/gate linears
    route to the SGL kernel, remaining dense linears to oneDNN -- both paths
    exercised in one model.
  • gpt-oss-20b (MoE, mxfp4 experts / bf16 dense+router): router linears route
    to the SGL kernel, dense linears to oneDNN.

Kernel-level microbenchmarks (oneDNN vs SGL, geomean over 5 trials x 20 iters)
for router/gate-shaped GEMMs across the M range confirm SGL wins throughout,
e.g. for a (K=1536, N=64) bf16 gate shape (granite-4.0-h-tiny):

M 1 8 32 128 512 2048 4096
oneDNN/SGL 0.50 0.41 0.54 0.55 0.89 1.00 0.98

(values < 1 favor SGL; consistent with the existing kernel benchmark sweep
data for other router/gate shapes, e.g. Qwen3-30B-A3B's (K=2048, N=128) and
gpt-oss-20b's (K=2880, N=32).)

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

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

@mergify mergify Bot added the quantization label Aug 7, 2026
@bigPYJ1151 bigPYJ1151 changed the title [CPU] Restore sgl-kernel dispatch for small unquantized GEMMs [CPU] Restore linear dispatch for small unquantized GEMMs Aug 7, 2026
@bigPYJ1151
bigPYJ1151 force-pushed the cpu-restore-sgl-small-gemm-dispatch branch from cbd6320 to 82c9d63 Compare August 7, 2026 09:11
PR vllm-project#50801 removed the SGLang AMX weight_packed_linear path from the
unquantized (bf16/fp16) linear dispatch, leaving oneDNN's onednn_mm as the
only CPU kernel. For small weights -- most notably MoE router/gate
projections, where N is the expert count rather than a hidden-size-scaled
dimension -- oneDNN never reaches its compute-bound regime no matter how
large the batch gets, so SGL's lower per-call dispatch overhead wins
across the full measured M range. Restore that dispatch, gated by a
weight-size threshold so larger dense projections (qkv/o_proj/gate_up/
down/lm_head) keep using oneDNN once batch size grows past decode-sized M.

Also add a runtime AMX-FP16 capability check: AMX-BF16/INT8 (amx_tile)
and AMX-FP16 are separate CPU ISA extensions (e.g. Sapphire/Emerald
Rapids expose the former but not the latter), and SGL's
can_use_brgemm<at::Half> always attempts brgemm for fp16 regardless of
M, so fp16 needs its own capability gate rather than piggybacking on
amx_tile.

Signed-off-by: jiang1.li <jiang1.li@intel.com>
@bigPYJ1151

Copy link
Copy Markdown
Member Author

/ci run

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown

✅ Triggered Buildkite CI #82833 for commit 82c9d6368889.

@bigPYJ1151

Copy link
Copy Markdown
Member Author

/ci run

@github-actions

Copy link
Copy Markdown

✅ Triggered Buildkite CI #83080 for commit 4e1a29b23a1b.

@bigPYJ1151
bigPYJ1151 merged commit 7ce84b9 into vllm-project:main Aug 10, 2026
94 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants