metal: bypass DSpark speculation once a request proves unprofitable - #965
Open
rinaldofesta wants to merge 1 commit into
Open
metal: bypass DSpark speculation once a request proves unprofitable#965rinaldofesta wants to merge 1 commit into
rinaldofesta wants to merge 1 commit into
Conversation
On Metal every verified DSpark row re-streams its routed experts, so speculation on text the proposer cannot predict runs slower than plain decode. The README measures 36-44 t/s against 46.5 t/s plain on prose. The scheduler already pauses and re-probes, but it never gives up, so the loss repeats for the whole request. Track accepted drafts and scheduler cycles for the lifetime of the request. Once two probe windows have run and the lifetime average falls below 0.5 accepted drafts per cycle, disable speculation for the rest of the request, the same bypass the gfx1151 fast path already takes. The rule uses counters, not timings, so a greedy request follows the same schedule on every run. Measured on a MacBook Pro M5 Max 128 GB, Metal, DeepSeek V4 Flash 0731 IQ2_XXS/Q2_K, greedy, ratios read at the first bypass decision: 8192 tokens of Italian prose 0.25 (bypass fires, decode 35.9 -> 39.2 t/s against 40.7 plain), reasoning with thinking 1.25 (no bypass, 47.9 t/s kept), short English prose 1.75 at the first decision (no bypass, stays a mild loss at 41.6 vs 45.0 plain, out of scope here), Python code never reaches the decision (54.7 t/s kept). Output stays byte-identical across scheduler variants on the reasoning prompt; the existing batched floating-point divergence of --dspark is unchanged. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
On Metal,
--dsparkis slower than plain decode on text the proposer cannot predict. The README measures 36-44 t/s against 46.5 plain on prose, and I get 35.9 against 40.6 after 8k tokens of Italian prose. The scheduler already pauses and re-probes on a bad window, but it never gives up, so the loss repeats for the whole request.Change, 19 added and 3 edited lines in
ds4.c: track accepted drafts and scheduler cycles for the lifetime of the request. Once two probe windows have run and the lifetime average is below 0.5 accepted drafts per cycle, disable speculation for the rest of the request, the same bypass the gfx1151 fast path already takes. Counters, not timings, so a greedy request follows the same schedule on every run. No new flags. The bypass is sticky for the request, like the gfx1151 one: a response that opens with unpredictable prose and later turns into code keeps plain decode. Reasoning text sits well above the floor, so the agent's usual think-then-edit turns are not affected.Why 0.5 and not higher: the ratio the rule sees at its first decision point does not rank text the way full-run profit does. On this machine, reasoning with thinking reads 1.25 at the first decision and gains 6.5% from speculation; short English prose reads 1.75 at the first decision, then decays to 0.88 over the run, and loses 8%. A floor that would catch English prose would also catch reasoning. 0.5 catches only the regime where every verified row costs more than it saves, with a 2.5x margin below reasoning. English prose stays a mild loss, out of scope here.
Measured, MacBook Pro M5 Max 128 GB, Metal, DeepSeek V4 Flash 0731 IQ2_XXS/Q2_K, greedy:
The reasoning prompt produced byte-identical output across four runs with the bypass on and off. The pre-existing
--dsparkcaveat about batched floating-point order is unchanged;--dspark-strictstill gives one-token-decode equivalence.Validation:
make dspark-verify-depthOK withworst_argmax_gap=0.000;make dspark-acceptanceOK,c_addaccepts 21 drafts with no bypass and 4 of 5 cases match the plain baseline byte for byte, the fifth (hello) being the pre-existing allowed divergence;./ds4_test --chat-multimodal-text-only,./ds4_test --server,./ds4_agent_testOK; Metal build clean. Nods4_testcase reaches this branch, since the only DSpark unit test runs with the scheduler disabled; coverage is the fixture plus the measurements above. Not run: CUDA, ROCm, GLM. The rule is gated on the Metal backend, so other backends are untouched.A first version of this used a second rule that bypassed after one all-miss window plus two environment knobs. The all-miss rule fired on reasoning and cost 3.1 t/s there, so it is gone, and so are the knobs.
Implemented with the help of a coding agent (Claude Code and Codex) and reviewed locally by the author.