Repository navigation
[explore] W4A8 sdot4 ranked shapes + test plan (not dest) - #9
Closed
BlivionIaG wants to merge 7 commits into
Closed
BlivionIaG wants to merge 7 commits into
BlivionIaG wants to merge 7 commits into
Conversation
Scaffold Explore-only research docs and an unwired HIP shape-(1) sketch for W i4 × A i8 → sdot4 on gfx1030. Not dest, not UNC-26, not in VLLM_ROCM_EXT_SRC / can_implement / serve scripts. Co-authored-by: Cursor Grok 4.6 Signed-off-by: Blivion <kev29lt@gmail.com>
This was referenced Sep 14, 2026
|
I've been thinking about this too. |
Merged
…ness Rework the Explore-only W4A8 (W uint4 x A int8 -> v_dot4_i32_i8) scaffold for gfx1030. Still not dest, not UNC-26, not in VLLM_ROCM_EXT_SRC, torch_bindings.cpp, can_implement or serve scripts. Contract fixes (README "What changed vs the first scaffold"): - ConfigA's "LDS=0" is LDS_PAD=0; ConfigA stages A in LDS. Shape (1) now follows ConfigA; the no-LDS variant is (1b), A via the scalar cache. - Packs are uint4 with zero points and exllama-shuffled by gptq_shuffle: zero-extend with a 3-VALU SWAR unpack, fold z*sum(a) per group, write A in the matching byte order (W stays shared with W4A16 decode). - Grouped scales make "i32 through K" impossible: i32 per group, f32 across groups. Ceiling ~1.5x main-loop VALU at G=32, ~1.9x at G=128. Draft and tooling: - csrc/rocm/explore/w4a8_sdot4.cuh: GEMM (7 sweep configs x G 32/64/128), tile-interleaved act quant, G0 issue-rate probes; compiles for gfx1030 with plain clang via w4a8_sdot4_isa_shim.h. - w4a8_sdot4_capi.cu: C ABI .so for the harness (hipcc, not CMake). - benchmarks/kernels/w4a8_sdot4_explore: NumPy oracle with error bounds, ISA audit (exact v_dot4 count per group, no spills, scratch or quarter-rate multiplies), V620 harness (G0 peak, G2 check, G3 bench vs the production W4A16 selector), G1 fake-quant accuracy script, CPU tests. - DESIGN.md (draft of the kernel); TESTPLAN.md split into agent-side checks and the V620 run, with blank result tables. Not run on a GPU. Agent-side: 56 tests pass with torch (50 + 1 skipped module without), isa_check clean with clang 18.1.3, pre-commit clean. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012RQWdM7SmvDHYCzew7dJ1c
Survey of JartX/vllm perf/rdna3_full_stack (dafcde3) and the related upstream work (vllm-project#57925, vllm-project#55522, vllm-project#54706, 1e48f8c). Each finding that applies to gfx1030 becomes a check here: - The exllama fp16 dequant stores s*(-1024 - z) as fp16, and gfx1030's qdq_4_rdna2.cuh does the same. reference.w4a16_rdna2_weights models it bit for bit: 2.3-3.3% rel-L2 against exact on random data, several times the per-token A8 error on Gaussian rows. G1 is therefore read as pessimistic, and G2 compares the W4A16 op with both exact and baked. - Per-(token, group) activation scales (llama.cpp's Q8_1 idea) as the *_ag configs (a16_lds_k32_ag, a8_lds_k32_ag), with a per-group act quant that needs no block reduction and --act-group-size in the G1 script. Outlier A8 error goes from 5.3-6.0% to 1.0% at G=32 and 1.9% at G=128; the compiled VALU ratio is 1.36 instead of 1.47 at G=32. - Deterministic split-K: G2 runs fp16 split-K twice and records whether the bits repeat. Graduation needs f32 partials plus a fixed-order reduce, or split 1. G3 gains --split-k to time the no-split case (JartX splits only below ~2x wave oversubscription). - G3 checks every timed output against the W4A16 op (rel-L2 < 0.1) and exits non-zero otherwise. On gfx1100 a corrupted engine benchmarked faster. - Graduation plan: the M threshold goes in the C++ op entry; W4A8 gets its own TU with a W4A16 ISA diff; soak runs use a checker proven on a known-bad sample. Shape (4) waits for a fails-first harness, since dense dequant + rocBLAS wrote "!!!!" in production on gfx1100. - isa_check: fall-through "; %bb.N" blocks are parsed separately, so preheader and loop-exit code no longer counts as loop body. Not run on a GPU. Agent-side: 62 tests pass with torch (54 pass and 1 module is skipped without it), isa_check is clean with clang 18.1.3 (non-_ag rows identical to ba8ce98), and pre-commit is clean. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012RQWdM7SmvDHYCzew7dJ1c
…pect the hard LDS cap - isa_check: clang 23 omits some asm keys (NumSgprs) for act_quant kernels, so the audit crashed with KeyError; use .get() with placeholders. - pick_split_k: the soft 16/64/32 KiB budget ignored the hard 64 KiB cap that launch_gemm enforces via the A_SRC-aware ex::lds_bytes, so it could return a split the launch rejected (kLdsTooBig). Clamp on the launch contract. - bench check: print each cell and record an explicit SKIP for ineligible cells instead of aborting the whole run. Measured after the fix on V620 (this branch): G0 sdot4/fdot2 MAC ratio 2.01 (PASS, implied 2.05 GHz); ISA audit all 27 configs ok, best a8_lds_k32 at 1.53x (G=32) / 1.77x (G=64) / 1.92x (G=128) VALU ceiling; G3 hot speedups 1.75-2.9x vs the production W4A16 op with rel-L2 ~2.5e-2; G2 180/192 pass (remaining = LDS-ineligible config/cell pairs, now explicit skips).
…eval Passing gpu_memory_utilization inside --llm-kwargs raised TypeError (duplicate kwarg), so production flags (kv_cache_memory_bytes, VL mm limits) could not be passed through. Merge harness defaults with llm_kwargs instead. G1 with this on a dense 1.5B: per-token int8 FFN activations FAIL (+10.77% PPL vs the +2% limit); per-(token, G=32) PASS (+0.75%; prefill-only +0.56%). The 27B target (cyankiwi/Qwen3.8-27B-AWQ-INT4, qwen3_5 hybrid) loads only with the production VL limits + KV cap and then yields NaN PPL under a bare LLM(), so its G1 still needs the fork's model env.
…ion groups - --clip-frac saturates the int8 grid at clip_frac*absmax, so the per-token outlier hypothesis can be tested from the harness. - fake_quant_int8 now reports a clear error when the activation group does not divide the per-rank (sharded) K, instead of torch's opaque unflatten failure. G1 investigation (dense 1.5B, prefill-only): per-token FAILS (+10.77%), and clipping makes it worse (0.9x -> +19.16%, 0.8x -> +59.94%), so the extremes carry signal; the fix is group granularity: per-(token, G=32) +0.75% PASS and per-(token, G=64) +0.72% PASS (G=128 invalid at TP=4: 128 does not divide the 2240-wide per-rank K).
…0 pass, next round Review of the first V620 pass (a1193e8, 1d601a9, 93caa86): - G2's 180/192 never covered a production-shaped cell. The f32 check runs at split 1, which needs M_TILE*K bytes of LDS: over 64 KiB for every LDS config at K=8704, and for a32n2 at K=2560. The first config that could not launch aborted the whole cell, so the 12 "skips" were 128x6144x2560, 624x6144x2560 and 2048x2560x8704 in full, and the 180 passes were the five EDGE cells. Now lib raises LdsTooBig; check_cell marks the f32 check n/a for that config and still bound-checks its fp16 path. It skips a config only when no group-aligned split fits (a32n2 at G=128, K >= 8704), and skips no longer count as failures. - G3 would have aborted the same way under --split-k 1 or --group-size 128. It now validates each launch once and records a skip. --configs ag selects the per-group configs, the only kind that passed G1. - The pick_split_k clamp from a1193e8 cannot change a split: the loops before it already stop within the <= 64 KiB soft budget or at the last split. An exhaustive sweep of 20,000+ cases found none it changes. Left in place, documented in RESULTS. Built on the results: - New config a8_smem_k32_ag (id 9): per-group scales, A through scalar loads, no LDS, so it is the one per-group config that can run split 1 at K=8704. The ISA audit (clang 18) is clean: 104-105 VGPRs, occupancy 9, 1.39x/1.68x/1.86x. a16_smem_k16_ag was tried too and spills SGPRs at G=128, so it is not added. - RESULTS-2026-09-28.md: the measured gates, the review, and a prioritized next round with each item tied to a result. P0 covers full G2, G3 on the _ag configs, counters, and G1 on the 27B. P1 covers mixed per-layer granularity, one A scale per R weight groups, K-chunked A staging and act-quant fusion. P2 covers G1 on the #31 exact build and G3 against the op serving runs (#30). - README status per gate. Shape (1d) becomes the main line. TESTPLAN and DESIGN get the new config and the skip semantics. On CPU: 54 passed and 1 skipped without torch, 64 passed with torch (including new tests for the K=8704 skip behaviour in check and bench). isa_check is clean on all 30 kernels. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012RQWdM7SmvDHYCzew7dJ1c
Author
|
Next actions after the first V620 pass (head 96b2a05; details in Updated 2026-09-29 after rechecking Where it stands:
Before the next pass
P0: runs on the V620 (harness from 96b2a05; the
|
Author
|
Superseded by landed work on rdna_extras (merge 3a0786e): the W4A8 dense + MoE kernels ship opt-in with op-level tests, ISA gates and in-model validation; the explore's accuracy conclusion (per-(token,group) scales only) and config choices are encoded in the shipped kernels. Remaining P0/PL items were perf-headroom gated on counters that are not being pursued. Closing. |
wsantos
pushed a commit
to wsantos/vllm-rdna
that referenced
this pull request
Oct 4, 2026
…efill replacement Adds the production wiring for the validated explore kernel (PR opengfx1030#9): - csrc/rocm/w4a8_sdot4_rdna2.cu / .cuh (own TU; no existing TU touched) with two ops returning int64_t status (0 ok, positive hipError_t, negative not-eligible code so Python falls back): * w4a8_act_quant_rdna2(x, group, a_i8, a_scale, a_asum) - per-(token, group) int8 quant + f32 scales + int32 group sums in the [T][K/8][MT][8] layout * w4a8_gemm_rdna2(a_i8, w_packed, qzeros, scales, a_scale, asum, out, k, group, zero_offset, config_id, split_k) - over the SAME packed W4 buffer RDNA2W4A16LinearKernel already leaves behind. Default config id 8 (a8_lds_k32_ag) with GROUP=64 (the measured accuracy point); groups 32/64/128 supported; the hard 64 KiB LDS cap is honoured when picking a split. - CMakeLists.txt: new TU in VLLM_ROCM_EXT_SRC for gfx1030; ops.h declarations; torch_bindings.cpp registrations (single def+impl pair). - rdna2_w4a16.py: opt-in prefill branch (VLLM_RDNA2_W4A8_SDOT4=1 + on_gfx10x + ops present + shape/quant eligibility), falling back to gptq_gemm_rdna2_prefill otherwise. Default OFF - byte-identical behaviour when unset. Existing dispatch chain untouched. - tests/kernels/quantization/test_rdna2_w4a8.py: act_quant vs numpy, W4A8 vs the W4A16 prefill op (rel-L2 < 0.1) for G=32/64/128, dispatcher default-off. Needs a single-rank TP group (default_vllm_config + probe-and-init helper). - docs/rdna2/w4a8-wiring.md. Validated on 4x V620 (venv-7.14.0_0.28.0): _rocm_C builds clean, both ops registered, 17/17 tests pass. Wired-path A/B vs the production W4A16 prefill op (act_quant + gemm, G=64): M=128 1.10x, M=512 1.55x, M=2048 1.78x, M=2048/K=8704 2.09x, rel-L2 ~1.3e-2. Still open: in-model validation needs a dense W4A16 checkpoint (the 27B AWQ bring-up currently resets the host); determinism at split_k>1 (pk4 CAS).
This was referenced Oct 11, 2026
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.
Purpose
Explore-only research scaffold for W4A8 = W i4 × A i8 →
sdot4(__builtin_amdgcn_sdot4/v_dot4c_i32_i8) on gfx1030.This is not dest, not UNC-26, and not a default path. It exists so other maintainers can research optimal tile shape.
Project 4 card: Explore: W4A8 sdot4 — ranked shapes (nibble→i8) (V620 inference).
Why this is not a duplicate
gh pr list/ GitHub search onopengfx1030/vllm-rdnaandvllm-project/vllm: no open PR for W4A8 sdot4 / ranked shapes.What landed
docs/explore/w4a8-sdot4/README.md— contract, ranked shapes, leave list, dependency.docs/explore/w4a8-sdot4/TESTPLAN.md— V620 cells to fill (no fabricated numbers).csrc/rocm/explore/w4a8_sdot4_shape1.{cu,cuh}— shape (1) sketch only. Not inVLLM_ROCM_EXT_SRC. Not intorch_bindings.cpp. Intended gate remainsVLLM_RDNA2_W4A8_SDOT4=0.Ranked shapes (do not skip)
K_STEP ∈ {16,32}only, twosdot4per W dword; inner loop must cover fullK_STEP(ConfigH lesson).Leave list
sdot8/V_DOT8_I32_I4,sudot4, FP8-bitsdot4, permanent TP≤2, unpack→fdot2sold assdot4.A8 is GEMM activations only (routed expert / dense FFN already on W4 packs). Do not requant leftovers / embed / head / norms / GDN state / KV / indexer.
Dependency
Explore after W8A8 INT8
sdot4exists. UNC-26 EXL3 stays first on dest.Test Plan
csrc/rocm/explore/is not inVLLM_ROCM_EXT_SRC.can_implement/ serve-script / EXL3 / FA edits.docs/explore/w4a8-sdot4/TESTPLAN.md(do not invent tok/s).git diff origin/rdna_extras -- CMakeLists.txt csrc/rocm/torch_bindings.cpp # expected: emptyTest Result
AI assistance was used to draft the explore docs and the unwired HIP sketch. A human submitter must review every line before this leaves draft.
Do not merge. Keep draft.