Repository navigation
perf(cuda): gate int4 f16 GEMV pipe vs plain by launch occupancy - #1501
Merged
Merged
Conversation
The block-32 scales-fp16 int4 MatMulNBits decode GEMV has two occupancy
regimes. The prefetch-pipelined ("pipe") entry uses more registers to hide
the Long-Scoreboard weight-load latency, which is a net win on grid-starved
(warp-capped) projections but a net LOSS on launches that already fill the
SMs many waves over, where its lower occupancy dominates.
Measured on qwen3.5-0.8b-fp16io (H200, 132 SMs):
- Wide LM head (N=248320, grid=31040 ~235 CTAs/SM): plain 85.0us vs
pipe 98.8us (-14% on that kernel).
- Grid-starved projections (N=4096, grid=512 ~3.9 CTAs/SM): pipe 4.66us vs
plain 4.79us (pipe still wins, kept).
Route well-occupied launches (ceil(N/cols) >= mp_count*32 CTAs) to the
lower-register plain entry; keep the pipe entry for grid-starved ones. Both
entries are BYTE-IDENTICAL (same lane->nibble mapping, same fp16 accumulation
order) so this is a pure occupancy/register trade, not a numeric change.
End-to-end paired A/B (interleaved, env-toggled on the same binary):
gate-ON beats the old all-pipe path by +1.3 to +1.6 tok/s every round
(~242 -> ~243.5 tok/s). Greedy tokens byte-identical (gate on == off), and
the qwen35_0_8b_text_decode_lock golden lock PASSES.
General (no hardcoded shapes: keys only on N, launch width, live SM count),
capture-safe (launch-time constant, stable across CUDA-graph replays), and
opt-out via ONNX_GENAI_GEMV_PIPE_WELLOCC=0 (forces the pre-gate all-pipe
behavior). Deep-prefetch (PF>2) was evaluated and reverted: short-K (K=1024)
int4 GEMV has too little per-warp work to hide latency and split-K would
reorder the fp32 reduction (not byte-identical) -- the grid-starved
projections are at their byte-identical latency floor.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
justinchuby
added a commit
that referenced
this pull request
Aug 19, 2026
…1502) Scribe consolidation after PR #1501 merge. Appends the int4 MatMulNBits GEMV occupancy-gate decision to decisions.md and a #1501 entry to gaff history. State files only. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
justinchuby
added a commit
that referenced
this pull request
Aug 19, 2026
Consolidates the LinearAttn warp-coop (#1503) decision + gaff history, and sweeps three inbox drops whose content is already in decisions.md (#1495/#1501/#1503). State files only. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
justinchuby
added a commit
that referenced
this pull request
Aug 20, 2026
#1519) Consolidation-only state PR (no code). Persists the campaign brain + decisions log to main after PR #1516 (int8 GEMV split-K, the 6th clean token-identical win) merged. ## What's in here - **`.squad/decisions.md`** — merges Deckard's corrected captured-replay attribution + Gaff's #1516 GEMV drop (22,963 → 25,954 bytes, under gate). - **`.squad/identity/now.md`** — new top verdict block: 6-win arc (#1486/#1495/#1496/#1501/#1503/#1516), fair gap 1.24× → **~1.057× ORT-ahead**, data-shuffle retired as a dead lever, honest ceiling ~260–270 tok/s reached → kernel-chasing stopped. - **`.squad/agents/{gaff,deckard}/history.md`** — appended. - **Removes** `.squad/decisions/inbox/gaff-gemv-bias-fusion.md` — it rode onto main via #1516's squash (tracked-inbox anti-pattern); already consolidated into decisions.md. ## Campaign standing Native qwen3.5-0.8b fp16io decode: **~263.8 tok/s** vs ORT eager ~279–290 = **~1.057× ORT-ahead** (from 1.24× at session start). Residual is a batch=1 launch/latency floor, not a buildable kernel lever. No manufactured levers remain. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #1501 +/- ##
===========================================
- Coverage 82.10% 80.25% -1.85%
===========================================
Files 12 377 +365
Lines 5471 166289 +160818
Branches 5471 166289 +160818
===========================================
+ Hits 4492 133462 +128970
- Misses 780 27994 +27214
- Partials 199 4833 +4634
Flags with carried forward coverage won't be shown. Click here to find out more. 🚀 New features to boost your workflow:
|
justinchuby
added a commit
that referenced
this pull request
Aug 20, 2026
- decisions.md: append #1501 compact entry (18,208→19,182 bytes; archive gate not triggered) - agents/gaff/history.md: #1501 landed entry + 4-win arc note - orchestration-log and log dirs are .gitignored; files written to disk only Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.
Lever: occupancy-gated pipe-vs-plain int4 MatMulNBits GEMV
The block-32 scales-fp16 int4 MatMulNBits decode GEMV has two occupancy regimes. The prefetch-pipelined (pipe) entry uses more registers to hide the Long-Scoreboard weight-load latency — a win on grid-starved (warp-capped) projections, but a loss on launches that already fill the SMs many waves over, where its lower occupancy dominates. This routes well-occupied launches to the lower-register plain entry and keeps the pipe entry for grid-starved ones.
Both entries are byte-identical (same lane→nibble mapping, same fp16 accumulation order) — a pure occupancy/register trade, not a numeric change.
Before/after ncu (H200, 132 SMs, isolated,
--graph-profiling node)Gate: route to plain when
ceil(N/columns_per_block) >= mp_count*32CTAs.End-to-end tok/s (qwen3.5-0.8b-fp16io, H200)
Paired A/B (interleaved, env-toggled on the same binary to cancel shared-box noise): gate-ON beats the old all-pipe path by +1.3 to +1.6 tok/s every round (~242 → ~243.5 tok/s). The within-round paired delta is stable even as absolute tok/s drifts 239–244.
Byte-identity / golden lock
qwen35_0_8b_text_decode_lockgolden lock PASSES (ok).scales_f16_pipeline_is_bit_identical_to_scalar,fp16_gemv_variant_selection_is_structural,fp16_gemv_matches_dequant_reference, plus newscales_f16_pipe_well_occupied_routes_lm_head_to_plain.Properties
ONNX_GENAI_GEMV_PIPE_WELLOCC=0restores the pre-gate all-pipe behavior.Honest floor
Deep prefetch (PF>2) was evaluated and reverted: the grid-starved int4 projections here are all K=1024 → only 4 weight loads/warp, too little per-warp work to hide latency, and occupancy is warp-capped (one warp per output column). Raising it would require split-K, which reorders the fp32 partial reduction → not byte-identical (barred). Those projections are at their byte-identical latency floor (already ~4.3–4.7µs/call, beating ORT's cited 4733ns/call). The one clean, free, byte-identical win is de-pipelining the well-occupied LM head.
Working as Gaff (CUDA-kernel specialist).
Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com