fix: apply rebase-audit fixes - #260
Conversation
|
Thanks for doing this audit — reconciling 366 diffs against a rebased tree is grim work and the disposition table is genuinely useful. Reviewed the code half; the audit tally itself I have taken as read rather than re-verifying 366 entries, so treat my comments as scoped to the four changed files. The rotation change is goodRemoving the 64KB One thing to fix: the The SET_ROWS ceiling-division change needs reworkThe premise does not hold for the path that matters, and the implementation is unsafe on the path where it would. In the KV path the tail case cannot arise. So Where non-aligned input can still reach the kernel, ceiling division is worse than floor. The group loop body unconditionally reads The new Suggested direction: mirror what Vulkan already does rather than changing the arithmetic. Metal's The CPU PPL regression is the most important line in this PRturbo3 at 8.04 against a 6.89 q8_0 baseline is a 17% degradation on the fork's flagship feature, and it is currently a footnote under "Known Issue". That deserves its own issue rather than living in a PR description — happy to open one if you have not. I have not verified the number myself and am not disputing it; I would want to know whether it reproduces on GPU or is CPU-path-specific before anyone goes hunting, since that alone halves the search space. On the recommendationsAgree on porting order, with one adjustment: Draft is the right state for this. Split the rotation fix out and it can land immediately — it is independently good and I have verified it. The SET_ROWS half wants the guard approach first. |
|
Took the verified half rather than leaving it queued behind the rest: It went in alone because it turned out to be cleanly separable — that commit contains only the stack fix and For your draft: rebase onto the branch tip and Also, |
|
Saw the new push. Three things, one of them time-sensitive. The branch is now conflicting, and the Vulkan TQ4_1S commit is duplicate work
Your own audit called this correctly ("Merge PR #259 — covers f03d331 + 8ba9f12"), so I think this is just a stale branch rather than a disagreement. Rebase onto the tip and drop The other two Vulkan commits (turbo3 KV pipeline, and the wiring correction) look like genuinely new ground that #259 did not touch — those are worth keeping, and I will review them properly once the branch is rebased and I can see them against current mainline rather than through a conflict. The PPL data is more interesting than the summary suggestsTwo observations that I think change how it should be read: Where the baselines are sane, turbo4 is at parity. qwen3.6-27b: f16 4.05, q8_0 4.06, q8_0/turbo4 4.07. kwaipilot-35b: f16 4.05, q8_0 4.03, q8_0/turbo4 4.02. That is a good result for the fork's headline feature and it is buried under the OSCAR2 rows. Where the baselines are not sane, the rows cannot support conclusions. gemma4-12b f16/f16 = 360 and gemma4-26b-a4b f16/f16 = 62456. A healthy model on wikitext does not do that at any chunk count — f16 is the control, and a broken control means rows 1-2, 5-6, 8-9, 11-12, 14-15, 18-19 are measuring something wrong with those specific converted models, not properties of oscar2. The analysis section reads it as "high but expected for small models on tiny context"; I do not think that holds, and it would be worth finding out whether those Also note this run is Repo hygiene
Rebase first and I will pick the review back up from there. |
- vulkan-shaders-gen: generate dequant_turbo3_0, get_rows_turbo3_0, get_rows_turbo3_0_f32, cpy_f32_turbo3_0, and cpy_turbo3_0_f32 SPIR-V - ggml-vulkan: register dequant, get_rows, get_rows_f32, cpy_f32_quant, and cpy_quant_f32 pipelines for GGML_TYPE_TURBO3_0 - ggml-vulkan: add TURBO3_0 to supports_op for GET_ROWS, CPY/DUP Assisted-by: Buffy (Freebuff)
- Fix dequant turbo3 workgroup size: {256*16} -> {128} (matches shader)
- Remove cpy_f32_turbo3_0 pipeline (non-SET_ROWS path lacks WHT)
- Add TURBO3_0 to get_cpy_pipeline for cpy_quant_f32 dispatch
- Remove TURBO3_0 from CPY f32->quant supports_op (no pipeline)
- vulkan-shaders-gen: remove turbo3 from cpy_f32 loop, add
standalone cpy_turbo3_0_f32 entry
The rebase already had all shader code from ff8bb73
(turbo_wht.comp, copy_to_quant.comp WHT quantization,
flash_attn turbo3 guards, flash_attn_base FA types). Only the
pipeline wiring needed correction.
Assisted-by: Buffy (Freebuff)
|
@TheTom working on the rebase now, the seperate PPL issue, I want to ensure that the fixed issues in the audit doesnt cause a conflict or possible may even resolve it, so I will address it when complete. |
266703a to
ff5b857
Compare
|
@TheTom PR is ready. |
|
Rebase worked — the stack fix and the SET_ROWS commit dropped out cleanly, and the surviving TQ4_1S commit is no longer duplicate work: post-rebase it adds It does not build with Vulkan enabled, though. On GB10, Root cause is the The fix is small — drop Worth reading #259's commit message on this specifically, because it predicted exactly this class of problem and the reasoning is still current. Beyond the duplicate-symbol break, that loop also emits for
So: drop the Two smaller things while you are in there:
|
ff5b857 to
e855ced
Compare
|
Builds now, and all three items are fixed — GB10, wave32,
No failures anywhere, and the 296 TQ3/TQ4 MUL_MAT cases from #259 still pass, so nothing regressed. But the new wiring is unreachable, so the commit does not yet do what it says. Every The pipelines are created but Two things needed to finish it:
Once those land the tests above will actually exercise the new path instead of skipping it, and I will rerun the same battery — at that point the numbers mean something, which they currently do not for these two ops. Worth saying: this is a good commit stuck one step short of done, not a wrong one. The shader-gen side, the |
0be525b to
ebe33da
Compare
|
The Claiming the op made the tests actually run, and the shader fails them. This is the good kind of bad news: the path was never being exercised before, so the green suite was measuring nothing. Now, wave32 / GB10 / 6 FAIL, 1 OK. Two things stand out:
Some signal on where to look, from the shapes rather than the shader:
Worth checking the No rush on this from my side. When you have a candidate I will rerun the same battery plus the full sweep on wave32, and it would be worth getting @Defilan's eyes on it too if he is willing, since he has the freshest context on how these pipelines are wired. For the record on process, this is the third time in this repo in a week that a green suite turned out to be skipping the path under test — #259's MUL_MAT_ID at n=16, #242's 0/0-reports-OK, and now this. Your commit is what surfaced it here; the tests were lying before you touched them. |
ebe33da to
ab7c73a
Compare
TQ4_1S SET_ROWS Broadcast Fix — Root Cause AnalysisDate: August 4, 2026 TheTom's Review Comment
Test results (wave32, GB10): 6 FAIL, 1 OK. Root CauseThe turbo2/turbo3/turbo4/TQ4_1S SET_ROWS Vulkan compute shaders in if (g >= p.ne / 32) return; // TQ4_1S (32-element blocks)
if (g >= p.ne / 128) return; // turbo2/3/4 (128-element blocks)
When the test harness later reads back those unwritten blocks, it encounters ExampleFor
For
FixChanged all 4 block-based SET_ROWS workgroup guards to use destination // OLD (broken for broadcast):
if (g >= p.ne / 32) return;
if (g >= p.ne / 128) return;
// NEW (accounts for broadcast expansion):
if (g >= gpr * p.ne21 * p.ne22 * p.ne23) return;Where:
When there's NO broadcast, File changed: Affected code paths: Additional Notes
|
|
Ran this on gfx1151 / RADV / wave 64 at the same head ( 24 tq4_1s SET_ROWS cases: 4 OK, 20 FAIL. The 4 passes are vacuous, which makes this worse than it looksEvery passing case is So every case that writes at least one row fails, including the simplest one — one row, no broadcast, contiguous: I think the bounds check is the cause, and I owe a correctionI first assumed the change from With that corrected:
Why turbo did not catch this: the turbo types are not in the generic SET_ROWS sweep — they have bespoke Two smaller thingsThe summary above says the single passing case was Second, worth a separate look rather than folding into the above: the decomposition does No sentinel mismatches on this box, across all 20 failures. Since the overrun reads garbage row indices out of Happy to test a candidate fix on wave64 whenever there is one. |
- vulkan-shaders-gen: add set_rows and cpy_tq4_1s_f32 SPIR-V (kept outside type_names to avoid duplicate dequant symbols and unsafe wave-size mul_mat_vec variants, per PR TheTom#259) - ggml-vulkan: register set_rows, cpy_quant_f32 pipelines; add get_cpy_pipeline and SET_ROWS dispatch; add to get_to_fp16 The rebase already had all shader code: dequant_tq4_1s.comp, mul_mat_vec_tq4_1s.comp, TQ4_1S blocks in copy_to_quant.comp, copy_from_quant.comp, dequant_funcs.glsl, and types.glsl. Only the C++ pipeline wiring was missing. Post-review: dropped \"tq4_1s\" from type_names (PR TheTom#259 already covers dequant/mul_mat_vec via explicit string_to_spv calls), removed duplicate pipeline_dequant registration. Assisted-by: Buffy (Freebuff)
ab7c73a to
5f5ef77
Compare
|
Thank you for the detailed trace and the wave64 run — that was exactly the kind of careful review this needed. You were right on all counts. What was wrong with the first fixThe original And you corrected my mistaken assumption that the bug was broadcast-specific — the minimal The new fixAfter decomposition, before any memory access, all four turbo SET_ROWS paths now check: if (i01 >= p.ne01 || i02 >= p.ne02 || i03 >= p.ne03) return;This keeps the destination-based global guard (covering broadcast rows) but prevents source overrun per-workgroup. The four affected paths in
Secondary decomposition issueYou flagged the RequestHappy to get a retest on wave64 whenever you have a moment — same battery: |
|
Retested The four "passes" are still the What did change is the error magnitudes, on every case:
So the guard is doing something — it suppresses the overrunning workgroups, which changes what lands in the destination — but the rows that do get written are still wrong. Why indexing is no longer my suspectI traced the minimal failing case by hand, That surviving set is exactly the three real source rows, and That points the remaining defect at the quantize-and-write math rather than the decomposition. It also explains why this never looked broadcast-specific: the simplest possible shape has correct indices and still produces wrong values. Worth noting the Suggested next probeThe minimal case is one row of 32-element blocks with correct indices, so the cheapest discriminator is a single-block end-to-end comparison: dump the Happy to run that on wave64 if useful — though you may get there faster on your own hardware, and I would rather not duplicate your work. Also happy to re-run the full battery on any next candidate. |
The TQ4_1S / TURBO2_0 / TURBO3_0 / TURBO4_0 SET_ROWS kernels decomposed the global workgroup index with the row_idxs tensor's ne2 as modulus (i02 = tmp % p.ne12), but the iteration space is the source tensor's dims. For r=1 shapes the slice index i03 = tmp / p.ne12 never advanced past 0, so only the first source slice was quantized and every slice wrote to the same destination row. The i02 >= ne02 guard masked the fault by dropping the bogus slots, which is why the 4-bit battery showed 4 OK / 20 FAIL with correct looking indices. Decompose over p.ne02 / p.ne03 instead, matching the generic SET_ROWS path and the CPU reference. test-backend-ops on Vulkan: SET_ROWS 343/343 (tq4_1s 24/24, was 4/24), SET_ROWS_TQ4_1S 17/17, MUL_MAT tq4_1s 148/148, CPY tq4_1s 5/5. Assisted-by: DeepSeek V4 Flash
|
I really need a amd device, i hate having to try to fix things and have no way to test. |
|
Totally get that. Happy to kick off anything you want me to try. I can dig into it too but don't want to step on your work |
|
I feel like I can only get so far, so if you have suggests or patches, please don't feel like you are stepping on any toes. |
|
And since this touched all four turbo paths, the full sweep to check for collateral: 24560/24560, 2/2 backends, zero failures. CPY is clean too at 252/252. Nothing regressed. The four cases that used to "pass" were the I owe you a correction, because I steered you wrongIn my last comment I said the remaining defect was in the quantize-and-write math, not the decomposition, and filed the I reached that conclusion from a hand-trace of What I should have taken more seriously is that the guard masking a wrong decomposition and the guard fixing it look identical from the outside until you correct the decomposition itself. On the AMD hardwareUnderstood, and no need to work blind on this. Send me any candidate and I will run the same battery — build plus Nice fix. The decomposition was the kind of thing that only shows up when a type finally reaches a sweep that varies |
|
Verified on wave32 and merging. GB10 / NVIDIA / warp size 32, head
Identical to @Defilan's wave64 numbers, down to the total. Two wave widths, two vendors, same result — and the four cases that used to "pass" were the vacuous zero-row ones, so this is 24 genuinely executing where 4 were previously measuring nothing. @giveen — this is the good version of a hard situation. You wrote a shader for hardware you do not have, took the review feedback through several rounds without getting defensive about it, and the thing that finally landed is correct. Saying "I really need an AMD device, I hate having to fix things and have no way to test" is also just true, and worth saying out loud rather than quietly shipping and hoping. The audit that started this PR is what surfaced the whole @Defilan — thank you for running his patches on your hardware. Catching that the four passing cases were passing vacuously is the kind of thing that only comes from actually reading the output rather than the summary line, and it is the reason this PR ended up correct instead of merely green. The two of you working the same problem from opposite ends — one with the context, one with the card — got further in an evening than either would have alone, and it is the pattern I would like more of around here. Merging. The remaining items from the earlier review (the rebase-audit findings, the PPL investigation) are yours to pick up whenever, no timeline. |
284ffc7
into
TheTom:feature/turboquant-kv-cache
Giveen's Rebase Audit — Final Report
Audit completed: August 4, 2026. Branch:
feature/turboquant-kv-cache.Final Tally
Key Finding
The rebase is significantly better than the original fork branch. Almost every diff fell into one of three categories:
Only pipeline wiring corrections were ever needed — never algorithmic changes.
Changes Applied to Codebase (5 commits on
giveen-says-sorry)37daf448550bec97263eca09aec53e9ceab7b17a494833d0dbfba0968be5ff8bb7394661266703a2bf03d331446e4All rebased onto latest
feature/turboquant-kv-cacheon Aug 4 (force-pushed togiveen/giveen-says-sorry).Unsure Folder Resolution (28 → 0)
All 28 "unsure" diffs were Metal experiments — every single one was already in the rebase or superseded:
Known Issue: CPU PPL Regression
CPU turbo3 PPL = 8.04 vs q8_0 baseline 6.89 (17% degradation). Cause unknown. Needs separate investigation of CPU quantization/dequant path.
PR #260 — Current State
giveen-says-sorry, rebased onto latestfeature/turboquant-kv-cache