dflash: port #219 onto feature (rebased full CL) - #220
Conversation
Take giveen's complete PR #219 change list (file content from turbo-dflash tip) and land it on current feature tip, instead of bulk-merging the master-based mega-diff. Included from #219: - DFlash/EAGLE3 model + arch + speculative stack deltas - Deferred KV injection + gemma gating - --dflash / --eagle3 / -cd convenience flags - server output_reserve / n_outputs accounting - qwen35 t_layer_inp for dflash extract - CUDA fattn.cu f16 extra-data helpers + turbo4 dequant paths from his tip - eagle3/dflash model rewrites as in his branch Tip-preserving follow-ups applied on top of his file content: - Restore #217 speculative gate (always probe seq_rm; only init when speculative enabled, including --dflash/--eagle3 flags) - DFlash metadata dual-load: LLM_KV_DFLASH_TARGET_LAYER_IDS then LLM_KV_TARGET_LAYERS (same GGUF key "%s.target_layers") - Do not resurrect deleted openai-moe-iswa.cpp Skipped: master-base history noise; deleted-on-tip paths. Verified: Metal build of llama-server + llama-cli green; --dflash/--eagle3 flags present in -h; short Qwen3.5-9B generation smoke on Metal. No local DFlash draft GGUF found, so end-to-end draft acceptance not run.
|
Sorry about the previous unclean PR, here is an updated benchmark DFlash Benchmark Sweep — PR #220 + flush optimizationHardware: RTX 5090 (32GB) · Intel Core Ultra 9 285K Qwen3.6-35B-A3BTarget:
Qwen3.6-27BTarget:
Gemma4-26B-A4BTarget:
Gemma4-26B-A4B-QATTarget:
Gemma4-31BTarget:
Gemma4-31B-QATTarget:
Optimized vs PR #220 baselineThe flush optimization (flush_injection outside per-chunk loop for non-deferred mode) is included in all DFlash results above. Key benefit for multi-chunk prompts:
Confirmed: no regression vs PR #220 baseline on any tested configuration. Notes
|
|
deferred-kv-injection-optimization.md This is an optional patch as well. |
|
I acknowledge the slow processing speed, I will need to evaluate if thats because of my code or because of the way DFLASH operates next. |
No problem at all. very happy to have contributors that are passionate about the project. please feel free to push commits on top of this one and i'll be revisiting it later today! |
DFlash Prompt Processing SpeedIssue: Prompt processing (prefill) is ~19% slower when DFlash speculation is enabled. This is not a bug in our branch. Mainline llama.cpp shows the exact same regression. MeasurementsAll tests: Qwen3.6-35B-A3B, Q4_K_S target, DFlash-Q8_0 draft, 1024 ctx, q8_0 cache, --reasoning off, RTX 5090 Mainline llama.cpp (HEAD, upstream)
Our branch (test-pr220)
The prompt penalty is identical (-19%) on both mainline and our branch. DFlash is working as designed. Root CauseDuring prefill, every ubatch chunk triggers the DFlash
The target decode and the encoder encode cannot overlap -- they share the same CUDA stream and the CPU needs to inspect the target's outputs before it can build the encoder's input. This serializes the GPU: target decode -> sync -> CPU copy -> encoder -> sync -> CPU stash -> next target decode. For a 512-token batch, the encoder matmul alone is ~69 GFLOPs (0.9x of one target model FFN layer). Not enormous, but it runs as a separate kernel launch with no overlap, adding latency to every prefill chunk. During generation (autoregressive, 1 token at a time), the encoder cost is negligible. The draft tokens provide a net speedup of 1.7-1.9x. The penalty is only during prefill. Why We Can't Easily Fix It Without RestructuringThe encoder output is needed before KV injection, and KV injection must happen before the draft decode. The chain is:
You can't defer the encode without also deferring the injection and draft. The current code already defers the injection to draft time (deferred mode), but the encode still runs per-chunk because the raw features are too large to stash efficiently (n_tokens x 8 x 4096 x 4 bytes per token). VerdictThe 19% prompt penalty is an architectural cost of DFlash, present on every implementation. It's worth paying: DFlash improves generation throughput by 77-93%, and the model spends most of its time generating, not processing prompts. |
|
I have a few patches that I will wait till apply after you merge that improves prompt processing a tiny bit. |
- common/speculative.cpp: cast n_seq to llama_seq_id in the deferred-flush loop (matches the other 22 identical loops in the file); was tripping -Werror=sign-compare on cuda/ubuntu-arm64 CI. - common/speculative.cpp: replace vector::assign(iter,iter) with resize()+std::copy() for the two DFlash encoder-output stash sites; the assign() path triggers a GCC/libstdc++ -Wnonnull false positive on the pre-allocation memmove (the source is already guarded by GGML_ASSERT(inp_g)). Same -Werror failure on both platforms. - ggml/src/ggml-cuda/fattn.cu: get_alloc_size() no longer computes/reserves space for the old in-dst-buffer K/V f16 scheme; launch_fattn already moved to pool_alloc (HIP: raw cudaMalloc/cudaFree) for that scratch, so the old struct + helper were dead code once alloc_size stopped calling them (nvcc -Werror on unused-function/unused-variable). Removed both and simplified get_alloc_size() to return ggml_nbytes(dst). Verified on RTX 5090 (sm_120): turbo3/turbo4/f16 PPL bit-exact to pre-PR values across every change, fused turbo2/turbo3 decode speed unchanged, the q8_0/iq4_nl mixed-KV fallback still completes without crashing, and a full -DLLAMA_FATAL_WARNINGS=ON build matching CI's exact flags is clean.
Merged: findings and verification summaryFull writeup of what changed and what was checked before merging this. Build fixes (the CI blockers)Two real
Both confirmed fixed on two independent platforms: a local build matching CI's exact Blast-radius verificationThis changelist does more than add DFlash: it also moves the K/V f16 scratch-buffer allocation for the TILE/WMMA/MMA flash-attention paths from space reserved inside
Also found and cleaned up one real leftover: One pre-existing, unrelated item I ruled out along the way: Remaining CI reds (cuda, hip, musa, hip-quality-check) all trace to the same UI-assets CDN download flake ( Thanks @giveen, this is a strong contribution, both the DFlash port itself and the deferred KV injection optimization (with the Gemma-vs-Qwen acceptance-rate analysis and the model-type gate) were well benchmarked and landed cleanly once rebased. One thing worth a follow-up if you have the cycles: your very first benchmark comment on #219 showed a consistent, large prompt processing (prefill) regression with DFlash enabled across every model tested, independent of the generation-side work, e.g. Qwen3.6-27B 203.3 -> 100.9 t/s, Gemma4-31B 385.4 -> 139.0 t/s, Gemma4-31B-QAT 487.8 -> 142.7 t/s. The deferred-injection patch addressed decode; prefill still takes that hit whenever |
Overview
Full rebased port of @giveen's DFlash work from #219 onto current
feature/turboquant-kv-cache.#219 was aimed at
master, so GitHub showed a huge unrelated fork delta. This PR is the same intended change list applied on top of current feature tip (TurboQuant / SYCL / recent fixes stay intact).Tom tried to keep giveen's intended changes as-is (file content from the
turbo-dflashtip for the DFlash CL paths).From #219 (kept)
--dflash/--eagle3/-cdconvenience flagsn_outputs/ draft accountingt_layer_inpfor dflash extractTip-preserving deltas on top of his content (small)
server-context(always probeseq_rm; only init when speculative is enabled, including--dflash/--eagle3). His branch had unconditional warnings/init.LLM_KV_DFLASH_TARGET_LAYER_IDSthenLLM_KV_TARGET_LAYERS(same GGUF key%s.target_layers).src/models/openai-moe-iswa.cpp(already removed on tip).Not taken
master(+200k history noise)Testing
llama-server+llama-clibuild green--dflash,--eagle3,-cdRequest for @giveen
Please test this branch the same way you validated #219 (
--dflash+-mddraft, turbo4/q8 caches, acceptance rate). If anything from your CL is missing or regressed, call it out and we will fix on this tip.Related
Thanks @giveen for the implementation and the extensive benches.