qwen35: batch DFlash2 decode for Qwen3.8-27B concurrency - #642
Conversation
|
@cubic-dev-ai review this PR |
@Graffioh I have started the AI code review. It will take a few minutes to complete. |
There was a problem hiding this comment.
All reported issues were addressed across 48 files
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
|
@cubic-dev-ai review this PR |
@Graffioh I have started the AI code review. It will take a few minutes to complete. |
There was a problem hiding this comment.
All reported issues were addressed across 53 files
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
f113f6d to
b5727de
Compare
fd1e7fb to
308f630
Compare
There was a problem hiding this comment.
renamed this into replay log in PR 651
eb78a9e to
5944b66
Compare
There was a problem hiding this comment.
5 issues found across 62 files
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/src/common/dflash2_head.cpp">
<violation number="1" location="server/src/common/dflash2_head.cpp:91">
P1: When singleton selector scoring receives selector codebooks whose vocabulary differs from the target, this validation accepts the layout and later gathers codebook rows using target-generated IDs. Populate `target_output_vocab` from `target.lm_head_tensor()` (and the declared target vocabulary when available) before validating, or reject the mismatch before `ggml_get_rows()`.</violation>
</file>
<file name="server/src/common/feature_gate.cpp">
<violation number="1" location="server/src/common/feature_gate.cpp:267">
P2: When the drafter width is below 16, this gate reserves 16 scratch tokens per lane while `Qwen35Backend` reserves the actual draft width. It unnecessarily rejects valid `--kv-pool-tokens` values; derive this cap from the resolved draft width or enforce the address limit only where that width is known.</violation>
</file>
<file name="server/deps/llama.cpp/ggml/src/ggml-vulkan/ggml-vulkan.cpp">
<violation number="1" location="server/deps/llama.cpp/ggml/src/ggml-vulkan/ggml-vulkan.cpp:15790">
P2: When intermediate output is enabled or a transition journal is requested, this predicate still admits the op to Vulkan even though the shader leaves those regions unwritten. Require `op_params[0] == 1` and `op_params[3] == 0`, or add shader support for those output regions.</violation>
</file>
<file name="server/deps/llama.cpp/ggml/src/ggml.c">
<violation number="1" location="server/deps/llama.cpp/ggml/src/ggml.c:5770">
P2: When `max_kv_seq_len` is near `INT32_MAX` and `block_size` is greater than one, this assertion admits the value, but the paged-attention launcher overflows while rounding `live_tokens` to blocks. Bound the launch bound including the rounding term, or perform that calculation in 64-bit before launching.</violation>
</file>
<file name="server/test/test_draft_swa_multilane.cpp">
<violation number="1" location="server/test/test_draft_swa_multilane.cpp:157">
P2: The test always fails before running its intended check: it passes the never-initialized `DraftFeatureMirror unused_ring` (target_feat=nullptr, cap=0) to `draft_kv_begin_step`, and every committed lane has n_new>0 so `copy_feature_ring_range_to_tensor` is called on the empty ring and returns false, making `begin_step` fail with "[draft-kv] feature copy failed" (or the bulk-append equivalent). The lane mask check, single-lane forward, and single-vs-packed comparison are therefore all unreachable. Initialize and populate the feature ring (draft_feature_mirror_init + fill committed rows) before the lane loop, matching how the production caller syncs the ring into begin_step.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
Restore the paged-attention C ABI through a separate tree entry point. Reject unsupported GDN variants, initialize root-only chain trees, and size draft metadata from graph capacity.
Keep GDN journals inside the result buffer, restore the 10-source tensor layout, validate every tree destination before mutation, and allow selector widths that use the CPU top-k fallback.
Validate singleton selector vocabularies and token IDs before codebook gathers. Reject unsupported GDN output layouts on Vulkan, and use overflow-safe ceil division in paged attention.
391a981 to
ed30620
Compare
Preserve paged-KV allocation order across rollback and destroy draft graphs before park frees their weights. Reject invalid GDN replay layouts and malformed SWA metadata. Exercise both grouped and scalar GDN dispatch paths.
|
@cubic-dev-ai review this PR changes related to qwen 3.8 27b DFlash 2 concurrency implementation |
@Graffioh I have started the AI code review. It will take a few minutes to complete. |
There was a problem hiding this comment.
All reported issues were addressed across 62 files
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
There was a problem hiding this comment.
All reported issues were addressed across 8 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
Stack
This PR is stacked directly on #625 at
910a2086. It contains seven #642 commits, ending at308f630f.The final #625 change after the benchmarked parent was test-only:
server/test/test_server_unit.cppnow expects disk-cache version 2. It does not change the server or runtime source.Summary
Add fixed-width DFlash2 speculative decoding to Qwen3.8-27B continuous batching.
--ddtreepath from qwen35: DSpark speculative decoding (Qwen3.8-27B drafters) #625.The concurrent path requires a selector-enabled local draft, same-device placement, paged full attention, and greedy sampling. Distribution-preserving sampled speculation is in the stacked follow-up #654.
DFlash2 sliding window
--draft-swa 2048changes the effective window without replacing the checkpoint's per-layer SWA pattern. Metadata-backed mixed and all-full patterns are preserved; legacy inference runs only when the metadata is absent. Applying the override twice is idempotent.The tested Qwen3.8 DFlash2 draft reports
SWA layers: 5/5 (window=2048). Three post-window lanes at committed positions 65, 81, and 133 matched singleton execution withmax_abs=0on both gfx1201 and gfx1151.Run concurrent DFlash2
Startup must report
SWA layers: 5/5 (window=2048)and[parallel-chain] fixed DFlash2 width=8. A speculative cohort reports[draft-kv-batch] packed backbone ready.W8 versus W16
I screened W8 and W16 with fresh servers, the same target, draft, prompt manifest, and SWA 2048 setting.
The refreshed #625 matrix produced 106.68 tok/s at C6 with W8, still 8.1% above the W16 median. W16 is noise-level at C3 and materially worse at C6, so this PR keeps the checkpoint-native W8 path. The experimental W16 prewarm commit is not in the stack.
Refreshed Qwen3.8-27B concurrency results
Each cell starts a fresh server. C is the number of live requests. Each completed cell contains 60 requests with temperature 0, natural EOS, and at most 64 output tokens. Prefix caching is disabled.
The deterministic manifest contains 15 entries from each checked-in code, GSM, math, and agent suite. Prompts contain 43 to 2,643 tokens, with a median of 107.5. Both modes use the same pure-IQ4_XS target, 4,096-token context, Q8_0 K/V, paged full attention, and 20 ms admission window. DFlash2 adds the Q8_0 draft, W8, and SWA 2048.
The refreshed R9700 matrix is complete: 720/720 requests, zero failures, and a 1.36x to 2.20x DFlash2 speedup over AR. The isolated Strix run completed 300/300 valid requests through C2 plus C3 AR. An unrelated shared-host CI job killed the C3 DFlash server and immediately started another GPU build, so that interrupted cell and C4-C6 are excluded rather than reported as measurements.
Goodput is total generated output divided by suite wall time, including prompt processing and scheduler retirement. Output-window throughput counts generated output between the first and last streamed tokens.
Artifact identity:
fd1e7fbcf1f9321d51eab2dd0198809cb550de13308f630f7eb379a1fd91902becd4ea22ab24910185e727625e4cca2b15acdc6e71934f020c3c65ac910a2086de7a7483f92699549353a133d936eaea; the only delta is the test expectation described above150fa0d5e30a7971ee258b6e42c2b33d778e4fc9dca18d55a1797a860921a816777cd45c4f78dfcca13b3e857dc7ff70ca7d9ab589ed50e7e2b338466cc62f4a4636a62b616ba3d429276d70328e80f02518f69ee74ee39ee6133d02506503ed{messages}SHA-256:72f03c07c46bec9ec32679a2dff937956a4c3d506792a65d4b6d903ad27bee13Verification
git range-diffreports all seven qwen35: batch DFlash2 decode for Qwen3.8-27B concurrency #642 commits patch-equivalent across the final qwen35: DSpark speculative decoding (Qwen3.8-27B drafters) #625 restack.308f630f.git diff --check.Scope
This PR excludes adaptive admission, cost models, DSpark batching, KVFlash, PFlash, and per-request sampling policy. #651 batches draft projections across lanes. #654 adds distribution-preserving sampled speculation.