perf(decode): default gate/up to 1-row mmvq2_qwen + rmsnorm load elimination (sm_120)#188
Open
thomasalvaedison7777-lgtm wants to merge 1 commit into
Conversation
…oving bit-identical output with in-place rounding. Update expert FFN Q4K to adjust environment variable handling for row-packing configuration.
1 task
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two small decode-path fixes from an nsys profile sweep on RTX 5090 (sm_120), Qwen3-30B-A3B-Q4_K_M:
SPARKINFER_GU_PACK2default from ON → OFF so Qwen3 decode uses the 1-row-per-blockgate_up_mmvq2_qwen_kernelinstead of the packedgate_up_mmvq2_pack2_qwen_kernel. Same 4-warp/row math and bit-identical output; smaller shared-memory reduction footprint on sm_120.add_rmsnorm2_q8micro-opt — reuse the bf16-rounded residual sum already in registers instead of store→reload fromout_sum, removing a dependent global load from this single-block, latency-bound kernel. Provably bit-identical bf16 round-trip.No env vars required; set
SPARKINFER_GU_PACK2=1to restore the old packed gate/up path.Proof of speedup
Tested on RTX 5090 (sm_120)
Decode tok/s (end-to-end, from
qwen3_gguf_bench;Qwen3-30B-A3B-Q4_K_M.gguf, 128 decode tokens):Main is latest
origin/main(8aa997a). The after value is the median of 3 repeated 4096-context runs below.RTX 5090, sm_120, CUDA 13.0.1 container, Release build
qwen3_gguf_bench Qwen3-30B-A3B-Q4_K_M.gguf 128
main vs branch: separate Release rebuilds per side
ctx=128: main 491.67, this PR 494.03
ctx=512: main 472.80, this PR 474.91
ctx=4096: main 393.91 / 393.97 / 394.29 -> median 393.97
this PR 395.66 / 395.48 / 395.31 -> median 395.48
Correctness: bit-identical — both gate/up kernel paths use identical math; the rmsnorm change is a provable bf16 round-trip (same token IDs as main on greedy decode).
Note: Gain is ~0.4%, near run-to-run thermal/clock noise on this box. Included for completeness per bot requirements; a scoreable win likely needs kernel-level fusion (Q/K/V projection is the top target at ~19% of decode).
Test plan
cmake --build … qwen3_gguf_bench)qwen3_gguf_benchat ctx=128, 512, and 4096 (128 decode tokens, bs=1)bench/scripts/bench.sh --downloadentrypoint verifiedbench/scripts/bench.sh --download # baseline (main)
bench/scripts/bench.sh --download # this branch (after)