Why
Paired measurement against the pinned graphed oracle (.agents/specs/dspark-spec-decode.md §6l):
| 35B cell |
ours |
pinned graphed vLLM |
ratio |
| "capital", 128 tok both |
75.82 |
77.28 |
0.981x |
| "fibonacci", 89 tok both |
135.39 |
155.60 |
0.870x |
Our fibonacci reps span 134.81-135.41 (0.4%), so 0.870x is a reading, not noise.
The deficit tracks acceptance. It is largest where the block is mostly
accepted, so the T=1+k verify runs every step (0.870x), and smallest where
acceptance is low (0.981x). That localises the gap to the VERIFY forward, not
the drafter: acceptance is at parity with upstream and our proposals are near
token-identical to theirs (#430).
Mechanism. Both model families gate the decode CUDA graph on
input.pure_decode (qwen3_5_dense.cpp:159, qwen3_5_moe.cpp:128), and
pure_decode is num_actual_tokens == num_reqs. A speculative verify submits
num_reqs x (1+k) tokens, so it fails that predicate and runs EAGER every step,
while upstream captures the uniform 1+k shape. §6g already established that the
graph launches we DO see are the D13 draft-step graph, not the verify.
This is the same headroom DFlash left open as D12 Part C.
Scope
- A verify-shaped capture keyed on
(num_reqs, 1+k). k is fixed per config and
num_reqs <= max_num_seqs, so the shape count is small and static.
- It must route the SPEC paths, not the pure-decode ones: block-diagonal causal
attention over the 1+k query span, and the GDN/Mamba T>1 spec recurrence with
per-timestep snapshots that SPEC-GDN-SEGMENTS already landed
(vt::GdnSpecDecode, vt::CausalConv1dSpecUpdate).
Qwen3_5DenseDecodeGraph as it stands is documented pure-decode ("all
query_len==1"), so this is a sibling class or an explicit generalisation, NOT
a loosened predicate. Do not simply widen the pure_decode gate: that would
send a spec batch through a graph captured for query_len==1.
Gate
- Replayed == eager BIT-IDENTICAL on both gate models, spec-ON and spec-OFF.
- spec-OFF byte-identical (the SACRED corpora), i.e. inert when not speculating.
- Then the paired cross-engine re-measure on the same two 35B cells above; the
target is >= 1.0x on both.
Capture-safety warning
No function-local upload temporaries inside the captured region. This repo has
already shipped a use-after-free from exactly that (a captured graph baked stack
addresses, replay read freed memory), and a sanitizer-clean run is NOT proof of
capture safety. Compute-sanitizer plus an explicit replay-vs-eager bit-compare.
Follows #436 (W7 device sampling, landed, byte-identical), which removed the
host-side sampling waste but not this.
Why
Paired measurement against the pinned graphed oracle (
.agents/specs/dspark-spec-decode.md§6l):Our fibonacci reps span 134.81-135.41 (0.4%), so 0.870x is a reading, not noise.
The deficit tracks acceptance. It is largest where the block is mostly
accepted, so the T=1+k verify runs every step (0.870x), and smallest where
acceptance is low (0.981x). That localises the gap to the VERIFY forward, not
the drafter: acceptance is at parity with upstream and our proposals are near
token-identical to theirs (#430).
Mechanism. Both model families gate the decode CUDA graph on
input.pure_decode(qwen3_5_dense.cpp:159,qwen3_5_moe.cpp:128), andpure_decodeisnum_actual_tokens == num_reqs. A speculative verify submitsnum_reqs x (1+k)tokens, so it fails that predicate and runs EAGER every step,while upstream captures the uniform
1+kshape. §6g already established that thegraph launches we DO see are the D13 draft-step graph, not the verify.
This is the same headroom DFlash left open as D12 Part C.
Scope
(num_reqs, 1+k). k is fixed per config andnum_reqs <= max_num_seqs, so the shape count is small and static.attention over the 1+k query span, and the GDN/Mamba
T>1spec recurrence withper-timestep snapshots that
SPEC-GDN-SEGMENTSalready landed(
vt::GdnSpecDecode,vt::CausalConv1dSpecUpdate).Qwen3_5DenseDecodeGraphas it stands is documented pure-decode ("allquery_len==1"), so this is a sibling class or an explicit generalisation, NOT
a loosened predicate. Do not simply widen the
pure_decodegate: that wouldsend a spec batch through a graph captured for query_len==1.
Gate
target is >= 1.0x on both.
Capture-safety warning
No function-local upload temporaries inside the captured region. This repo has
already shipped a use-after-free from exactly that (a captured graph baked stack
addresses, replay read freed memory), and a sanitizer-clean run is NOT proof of
capture safety. Compute-sanitizer plus an explicit replay-vs-eager bit-compare.
Follows #436 (W7 device sampling, landed, byte-identical), which removed the
host-side sampling waste but not this.