Skip to content

perf(deepseek4): fix DSpark fused-verify wide-q performance cliff on gfx1151#17

Open
DeanoC wants to merge 2 commits into
base/ds4-dspark-435dd26from
feat/ds4-fused-verify-wideq-fix
Open

perf(deepseek4): fix DSpark fused-verify wide-q performance cliff on gfx1151#17
DeanoC wants to merge 2 commits into
base/ds4-dspark-435dd26from
feat/ds4-fused-verify-wideq-fix

Conversation

@DeanoC

@DeanoC DeanoC commented Jul 11, 2026

Copy link
Copy Markdown
Collaborator

Fixes the DSpark fused-verify wide-q performance cliff on RDNA / gfx1151 for DS4-Flash. Single concern (the cliff), split into two commits:

  1. perf(deepseek4)boundary-align the fused-verify width (deepseek4_dspark_spec.cpp): cap the verify batch to the next ratio-4 compression boundary so the boundary sits at the batch's LAST token, which the fused-verify graph's fast path assumes (deepseek4_fused_verify.inc). A mid-batch boundary is correct but ~3× slower in compute.
  2. perf(cuda-hip)MMVQ default on HIP (ggml-cuda.cu): default LUCE_MMVQ_MAX_NCOLS to the MMVQ batch ceiling (MMVQ_MAX_BATCH_SIZE=8). The prior default (3) is the measured sm_86 crossover; on RDNA the MMQ / dequant→rocBLAS-GEMM path is ~3× slower than MMVQ at small spec-verify batches, so a q=4 batch fell off MMVQ into rocBLAS HGEMM at M=4.

The two only remove the cliff together, but each is independently correctness-preserving and non-regressing.

Benchmark — before/after

config q=4 verify q=4 tok/s
before 311 ms 8.5
+ boundary-align (commit 1) 206 ms 9.1
+ MMVQ HIP default (commit 2) 107 ms 16.6

q=4 verify 311 → 107 ms (2.9×); wide-q now scales ~linearly (q3 = 89 ms, q4 = 107 ms) instead of collapsing. The default adaptive greedy path (q≤3, sweet spot q3 = 18.0 tok/s) and the AR single-token path are unchanged.

Methodology

  • Hardware: gfx1151 (Strix Halo), ROCm 7.2.2, default power/clocks, full 128 GB unified-memory pool (GGML_CUDA_ENABLE_UNIFIED_MEMORY=1).
  • Workload: DS4-Flash-ROCMFP2 + DSpark drafter, real decode path (DFLASH_DS4_SPEC=1 DFLASH_DS4_FUSED_VERIFY=1), greedy (temperature=0), 127-token generation, identical prompt across configs.
  • Width control: forced-q sweep via /tmp/ds4_spec_q (adaptive width off) so each config is measured at the same q.
  • Timing: built-in DFLASH_DS4_TIMING=1 per-phase cumulative means ([ds4-spec-t] TOTAL), one warmup request discarded, single loaded server per sweep (weights identical/warm across configs).
  • Kernel attribution: rocprofv3 --kernel-trace (see below).

Why it was a cliff (rocprofv3 --kernel-trace)

At q=4 the dense MLA attention projections crossed the MMVQ→MMQ threshold and dispatched to rocBLAS FP16 GEMM at M=4 with 128×128 tiles: Cijk_*HB_MT128x128x32 (~34% of decode) + dequantize_block_rocmfp4_fast (13%) dominated the trace. Keeping them on MMVQ (which reads each dense weight once for all q columns) removes both. The width fix additionally keeps the ratio-4 compressor pool at the batch's last token.

Correctness

  • Perf-only changes: commit 1 only narrows the speculation width; commit 2 only changes kernel selection. Neither touches numerics.
  • Greedy output is bit-identical across all three configs above (same 127-token completion), verified on the DSpark decode path on gfx1151.

Notes

  • Base is base/ds4-dspark-435dd26 (the DSpark branch commit) so the diff is only these two changes.
  • Licensed under Apache-2.0; reproducible from public sources (ROCm + this tree, no closed-source deps).

Follow-up q-sweep — current operating point (improved draft accept, 2026-07-14)

Re-measured on the current DS4 baseline with the improved draft (higher accept rate), gfx1151, forced-q (/tmp/ds4_spec_q, adaptive off), greedy, 127-token, 2 prompts:

q_cap verify ms mean accept tok/s
2 ~81 ~0.83 ~18.3
3 ~109 ~1.46 ~19.2
4 ~138 ~1.94 ~18.5

q=3 remains the static optimum (~19.2 tok/s), and q=4 is now competitive (~18.5) — no longer the pre-fix cliff — confirming the wide-q path is healthy at the current operating point. q=4 still edges below q=3 on average because its verify cost grows faster than the extra accepted tokens (56 vs 52 ms/tok), though it pays off on individual high-accept steps (18.0 tok/s @accept 1.82 → 19.1 @accept 2.05).

A dynamic confidence-gated width (q=4 only on high-confidence steps) was explored to capture those steps but does not beat static q=3: the DSpark confidence head is currently over-confident and over-selects q=4, and boundary-alignment alone can't offset q=4's higher per-token verify cost. Recommendation: static q=3 pending confidence-head recalibration (a model-side follow-up).

@DeanoC DeanoC requested a review from a team July 11, 2026 11:09
DeanoC added 2 commits July 11, 2026 15:54
…o-4 pool

Cap the fused-verify batch to the next ratio-4 compression boundary so the
boundary sits at the batch's LAST token, which the fused-verify graph's fast
path assumes (deepseek4_fused_verify.inc). A mid-batch boundary is correct but
~3x slower in compute because the compressor pools mid-batch.

Benchmark (gfx1151 Strix Halo, DS4-Flash + DSpark, greedy, DFLASH_DS4_SPEC=1
DFLASH_DS4_FUSED_VERIFY=1, full unified pool, forced-q sweep via /tmp/ds4_spec_q,
127-token decode, DFLASH_DS4_TIMING cum-mean): q=4 verify 311 -> 206 ms.
Perf-only: only narrows the width; greedy output unchanged.
The prior default (3) is the measured sm_86 (RTX 3090) MMVQ->MMQ crossover. On
RDNA the MMQ / dequant->rocBLAS-GEMM path is ~3x slower than MMVQ at the small
batches a spec-decode verify produces, so a q=4 DSpark verify fell off MMVQ into
rocBLAS HGEMM at M=4. Default to the MMVQ batch ceiling (MMVQ_MAX_BATCH_SIZE=8)
on HIP so dense projections read each weight once for all q columns.

Benchmark (same setup as the width fix commit): q=4 verify 206 -> 107 ms on top
of the width fix; wide-q now scales ~linearly (q3=89, q4=107 ms). AR /
single-token path unaffected (already on MMVQ). Perf-only: kernel selection, not
numerics.
@DeanoC DeanoC force-pushed the feat/ds4-fused-verify-wideq-fix branch from 2e754f2 to a619c5c Compare July 11, 2026 12:55
@DeanoC DeanoC changed the title deepseek4/dspark: fix fused-verify wide-q performance cliff (gfx1151, 311->107ms) perf(deepseek4): fix DSpark fused-verify wide-q performance cliff on gfx1151 Jul 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant