Skip to content

perf(deepseek4): enable causal Flash prefill#512

Open
weicj wants to merge 10 commits into
Luce-Org:mainfrom
weicj:draft/deepseek4-safe-rocmfp2-flash-prefill-pr496
Open

perf(deepseek4): enable causal Flash prefill#512
weicj wants to merge 10 commits into
Luce-Org:mainfrom
weicj:draft/deepseek4-safe-rocmfp2-flash-prefill-pr496

Conversation

@weicj

@weicj weicj commented Jul 11, 2026

Copy link
Copy Markdown
Collaborator

Summary

Enable causal Flash prefill for DeepSeek4 ROCmFP2. The implementation defaults to an internal prefill batch of 128 tokens, the best passing prefill result from the sweep and workload comparison below; deployments can reduce it when tuning.

Stack: main -> #502 -> #503 -> #496 -> this.

Changes

  • Enable causal Flash prefill for the all-hot DeepSeek4 prefill path.
  • Batch the causal Flash prefill path internally, with 128 tokens as the prefill-selected default. DFLASH_DS4_FLASH_PREFILL_CHUNK can reduce it.
  • Route DeepSeek4 causal prefill through Flash attention while preserving per-token causal visibility.

Validation

Validation used DeepSeek-V4-Flash-ROCMFP2-STRIX.gguf on with ROCm 7.2.4, gfx1151, max_ctx=1048576, chunk=512, and fused decode.

Flash prefill internal batch Prefill p50 Result
16 24.20 tok/s pass
32 34.45 tok/s pass
64 43.49 tok/s pass
128 54.96 tok/s default: fastest passing prefill
256 25.67 tok/s rejected: semantic mismatch

The same model, GPU target, server arguments, and prompts are used for before (baseline), 64-token and 128-token comparison. The different workload shows how different prompt impact the prefill speed.

Workload PP / TG Baseline (prefill / decode) Causal Flash, 64-token batch (prefill / decode) Causal Flash, 128-token batch (prefill / decode; default)
Repeated hello text 4k / 128 20.84 / 21.2 tok/s 40.41 / 19.2 tok/s 60.45 / 19.5 tok/s
Repeated hello text 8k / 256 20.32 / 21.4 tok/s 40.37 / 18.1 tok/s 52.10 / 18.4 tok/s
Creative writing 1065 / 128 21.28 / 21.2 tok/s 22.87 / 19.8 tok/s 36.41 / 20.4 tok/s
Mathematics worksheet 932 / 128 21.32 / 21.2 tok/s 31.43 / 20.1 tok/s 38.68 / 20.5 tok/s
Bug-fix request with source 755 / 128 21.35 / 21.3 tok/s 33.24 / 20.1 tok/s 39.70 / 20.5 tok/s

The 4k throughput prompt repeats a small token pattern and concentrates MoE routing. Prose, mathematics, and code distribute tokens across more experts, which adds ROCmFP2 dequantization and routed-FFN work not accelerated by Flash attention; this accounts for their lower prefill rates than 60.45 tok/s.

All prose, mathematics, and code responses remained in the requested content type and contained no malformed text. Their generation cap was 128 tokens.

davide221 and others added 8 commits July 8, 2026 17:23
Ports the ROCmFP4/ROCmFPX ggml work (previously lucebox-ggml Luce-Org#36, on the
old submodule pointer) into the vendored server/deps/llama.cpp tree.

- ROCmFP4/ROCmFPX quant types + CPU reference conversions (ggml/rocmfp4,
  ggml/rocmfpx) and the ggml type-trait registrations.
- CUDA/HIP dequant, copy, getrows, MMVQ vecdot, MMVF, unary and FA paths
  for the new types.
- Fused DS4 hyper-connection op (GGML_OP_DS4_HC) with the register-resident
  sinkhorn kernel; inert unless emitted by the DS4 fused-decode path.
- DS4 SwiGLU split op plumbing for the fused FFN matvec paths.

Layered on current main, so the main-side ggml work is preserved
(fp64 RoPE reduction, Luce-Org#497 RDNA MMQ tile, LUCE_MMQ_DP_MAX_NE1,
MMVQ_MAX_MOE_BATCH_SIZE, fused dual set_rows, raw-span guard).

Review fixes on top of Luce-Org#36:
- ggml_ftype_to_ggml_type: handle the 11 new ROCmFPX ftypes (dominant-type
  mapping) so the enum switch is -Wswitch/-Werror clean.
- FP6 MMVQ vecdot: pad qs[] to avoid a stack over-read of the last window
  (bit-identical; the over-read bits were already masked out).
The non-HIP fallback of rocmfp4_get_int_from_codebook_16 /
rocmfp4_get_low_int_from_codebook_16 called get_int_from_table_16, which is
defined in vecdotq.cuh. TUs that pull in this header without vecdotq.cuh
(fattn-chunked.cu reaches it via the fattn dequant chain) failed to compile
under nvcc:

  rocmfp4_hip_codebook.cuh: error: identifier "get_int_from_table_16" is undefined

The HIP path never hit this (it uses __builtin_amdgcn_perm), so the ROCm CI
and the Strix build stayed green while the sm_86 CUDA build broke.

Fix: inline the generic table expander (the generic branch of
get_int_from_table_16, verbatim) as a static helper in this header, so the
fallback no longer depends on include order. Bit-identical; the HIP hot path
is unchanged.
Server-side DeepSeek V4 Flash changes from Luce-Org#494, rebased onto the vendored
ROCmFPX ggml tree (no submodule pointer). Byte-identical to the validated
Luce-Org#494 server files.

Correctness (default ON):
- Token-by-token prefill by default; chunked prefill only fits inside the
  raw SWA ring, so long prompts / multi-turn degraded. Chunked stays
  available via DFLASH_DS4_CHUNKED_PREFILL for short-prompt benchmarking.
- Clear the cache buffer at new-sequence prefill (kv_offset==0) so requests
  2..N are byte-stable instead of pooling over leftover compressor state.
- Route non-hybrid (all-hot) placement through the HC-complete layer-range
  path; deepseek4_step's non-hybrid branch is HC-less and generates garbage.
- Key the cached decode-attn graph on the flush pattern; the old key
  collided once the compressed-KV ring filled, reusing a stale-topology
  graph.
- Compressor decode graphs read state/comp-cache through the ggml_set_rows
  result tensors so the current-step writes are explicit graph dependencies.
- Default DeepSeek4 chat prefix when the request has no system message, so
  the ROCmFPX "Src" GGUF stops behaving like a base model under bare prompts
  (explicit caller system prompts are preserved).

Perf, byte-identical default:
- Persistent HC matvec pool (row-split preserves per-row accumulation order)
  and f16c dot kernels with scalar-order adds.
- Per-step decode scalar inputs uploaded in 2 tensor_sets instead of ~430.

Opt-in, default OFF (documented as not bit-identical):
- DFLASH_DS4_FUSED_DECODE single-graph decode with GGML_OP_DS4_HC.
- DFLASH_DS4_FFN_RAW_MMID / DFLASH_DS4_FFN_FUSED_COMBINE accumulation reorder.
- DFLASH_DS4_ROCMFPX_HC_GPU GPU HC pre-mix.
Return confidence scores from the fused Markov graph in the existing token-id synchronization, then select q=2/q=3/q=4 from cumulative prefix confidence. Compatible DSpark artifacts enable the policy automatically; artifacts without a confidence head retain the existing EWMA controller. No new deployment configuration is introduced.\n\nValidated on gfx1151: GSM+Math 10/10 at 29.25 tok/s weighted, within 0.8% of fixed q=4, with adaptive behavior retained on low-acceptance prompts.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 48 files

Not reviewed (too large): server/src/deepseek4/deepseek4_graph.cpp (~2,569 lines), server/deps/llama.cpp/ggml/src/ggml-cpu/ops.cpp (~78 lines) - if these are generated or fixture files, add them to ignored paths to exclude them from future reviews.

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="server/deps/llama.cpp/ggml/src/CMakeLists.txt">

<violation number="1" location="server/deps/llama.cpp/ggml/src/CMakeLists.txt:211">
P2: The `rocmfpx` sources are being added to `ggml-base`, but the companion test file `ggml/rocmfpx/test_rocmfpx.c` is not wired into any CMake target or CTest suite. That leaves the test uncompiled and unrunnable in CI, so regressions in the ROCmFP2/FP3/FP6/FP8 quantization paths could go undetected. Consider adding an `add_executable` and `add_test` target for `test_rocmfpx.c` so it builds and runs alongside the rest of the test suite.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread server/docs/DS4.md Outdated
Comment thread server/deps/llama.cpp/ggml/src/ggml-cuda/convert.cu
Comment thread server/deps/llama.cpp/ggml/rocmfp4/rocmfp4_hip_scale.cuh
Comment thread server/deps/llama.cpp/ggml/src/ggml.c
Comment thread server/src/deepseek4/deepseek4_backend.cpp Outdated
Comment thread server/deps/llama.cpp/ggml/src/ggml-cuda/fattn.cu Outdated
Comment thread server/deps/llama.cpp/ggml/src/ggml-cuda/fattn.cu
Comment thread server/deps/llama.cpp/ggml/src/ggml-cuda/fattn.cu
../rocmfp4/rocmfp4.c
../rocmfp4/rocmfp4.h
../rocmfpx/rocmfpx.c
../rocmfpx/rocmfpx.h

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The rocmfpx sources are being added to ggml-base, but the companion test file ggml/rocmfpx/test_rocmfpx.c is not wired into any CMake target or CTest suite. That leaves the test uncompiled and unrunnable in CI, so regressions in the ROCmFP2/FP3/FP6/FP8 quantization paths could go undetected. Consider adding an add_executable and add_test target for test_rocmfpx.c so it builds and runs alongside the rest of the test suite.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At server/deps/llama.cpp/ggml/src/CMakeLists.txt, line 211:

<comment>The `rocmfpx` sources are being added to `ggml-base`, but the companion test file `ggml/rocmfpx/test_rocmfpx.c` is not wired into any CMake target or CTest suite. That leaves the test uncompiled and unrunnable in CI, so regressions in the ROCmFP2/FP3/FP6/FP8 quantization paths could go undetected. Consider adding an `add_executable` and `add_test` target for `test_rocmfpx.c` so it builds and runs alongside the rest of the test suite.</comment>

<file context>
@@ -205,6 +205,10 @@ add_library(ggml-base
+            ../rocmfp4/rocmfp4.c
+            ../rocmfp4/rocmfp4.h
+            ../rocmfpx/rocmfpx.c
+            ../rocmfpx/rocmfpx.h
             ggml-quants.h
             gguf.cpp)
</file context>

Comment thread server/src/deepseek4/deepseek4_dspark.h Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 9 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="server/deps/llama.cpp/ggml/tests/CMakeLists.txt">

<violation number="1" location="server/deps/llama.cpp/ggml/tests/CMakeLists.txt:2">
P1: The test target `test-rocmfpx` will fail to compile because the source file `test_rocmfpx.c` includes `"rocmfp4.h"`, but the CMake target only exposes `ggml/include` and `ggml/rocmfpx` as include directories. The header lives in the sibling `ggml/rocmfp4/` directory, which is not in the include path. Any build with `GGML_BUILD_TESTS=ON` will produce a missing-header error. Add `${CMAKE_CURRENT_SOURCE_DIR}/../rocmfp4` to the `target_include_directories` call, or if the include is unused (the test does not reference any ROCmFP4-exclusive declarations), remove the `#include "rocmfp4.h"` line from the test source.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

@@ -0,0 +1,11 @@
add_executable(test-rocmfpx ../rocmfpx/test_rocmfpx.c)
target_include_directories(test-rocmfpx PRIVATE

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: The test target test-rocmfpx will fail to compile because the source file test_rocmfpx.c includes "rocmfp4.h", but the CMake target only exposes ggml/include and ggml/rocmfpx as include directories. The header lives in the sibling ggml/rocmfp4/ directory, which is not in the include path. Any build with GGML_BUILD_TESTS=ON will produce a missing-header error. Add ${CMAKE_CURRENT_SOURCE_DIR}/../rocmfp4 to the target_include_directories call, or if the include is unused (the test does not reference any ROCmFP4-exclusive declarations), remove the #include "rocmfp4.h" line from the test source.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At server/deps/llama.cpp/ggml/tests/CMakeLists.txt, line 2:

<comment>The test target `test-rocmfpx` will fail to compile because the source file `test_rocmfpx.c` includes `"rocmfp4.h"`, but the CMake target only exposes `ggml/include` and `ggml/rocmfpx` as include directories. The header lives in the sibling `ggml/rocmfp4/` directory, which is not in the include path. Any build with `GGML_BUILD_TESTS=ON` will produce a missing-header error. Add `${CMAKE_CURRENT_SOURCE_DIR}/../rocmfp4` to the `target_include_directories` call, or if the include is unused (the test does not reference any ROCmFP4-exclusive declarations), remove the `#include "rocmfp4.h"` line from the test source.</comment>

<file context>
@@ -0,0 +1,11 @@
+add_executable(test-rocmfpx ../rocmfpx/test_rocmfpx.c)
+target_include_directories(test-rocmfpx PRIVATE
+    ${CMAKE_CURRENT_SOURCE_DIR}/../include
+    ${CMAKE_CURRENT_SOURCE_DIR}/../rocmfpx)
</file context>

Comment thread server/src/deepseek4/deepseek4_backend.cpp
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.

2 participants