Repository navigation
[SGL ATOM] enable qwen3.8-flash mtp in sgl atom - #2385
Merged
Merged
Conversation
Contributor
🏷️ CI GuideRuns automatically on every eligible PR before approval:
Heavy model tests:
|
ZLkanyo009
marked this pull request as ready for review
September 24, 2026 07:51
ZLkanyo009
force-pushed
the
lingzha/qwenflash-mtp
branch
from
September 24, 2026 09:00
48a17cf to
37db59d
Compare
valarLip
approved these changes
Sep 28, 2026
zhangxinyuanliuhengyu
pushed a commit
that referenced
this pull request
Sep 28, 2026
Drop the 0.5.17 recognition shims now that main has #2385, but keep the draft-arch rewrite and HC hidden-width install. GDN pad stays on the split helper; ReplaySSM imports stay on the GDN backend. Co-authored-by: Cursor <cursoragent@cursor.com>
zhangxinyuanliuhengyu
pushed a commit
that referenced
this pull request
Sep 28, 2026
The Flash decode-graph helper still constructs CpuGpuBuffer, but merging Co-authored-by: Cursor <cursoragent@cursor.com> #2385 over that patch left the import behind.
zhangxinyuanliuhengyu
pushed a commit
that referenced
this pull request
Sep 28, 2026
The hook imported qwen3_8_flash_next_bridge.refresh_flash_decode_graph_ple, which is not in the tree, so every replay logged a warning and skipped. #2385 already aliases PLE to GDN's static mamba_cache_indices and does not rebuild PLE on replay. Keep the breakable-logits and replay-sync patches. Co-authored-by: Cursor <cursoragent@cursor.com>
Merged
9 of 10 tasks
zhuyuhua-v
pushed a commit
that referenced
this pull request
Sep 28, 2026
* [sgl+atom] Upgrade SGLang to v0.5.19 Bump SGLang docker pins to v0.5.19 and retarget Kimi/MiniMax pool bridges from the removed ModelRunnerKVCacheMixin onto KVCacheConfigurator. Co-authored-by: Cursor <cursoragent@cursor.com> * [sgl+atom] fix(sglang): keep K3/MiniMax bridges slot-safe on 0.5.19 Store K3 mem-fraction restore off the slots dataclass and attach MiniMax scale ABI on MiniMaxSparseKVPool without wrapping the upstream pool. Co-authored-by: Cursor <cursoragent@cursor.com> * [sgl+atom] fix(sglang): publish V4 empty_kv_indptr on plugin metadata SGLang V4 decode reads empty_kv_indptr during CUDA graph capture, but the bridge builds base AttentionMetaData and never attached that buffer. Co-authored-by: Cursor <cursoragent@cursor.com> * [sgl+atom] fix(sglang): return DSV4 draft backends as (stamp, backend) SGLang 0.5.19 unpacks draft attention factories, so Pro MTP3 died in scheduler init. Also publish empty_kv_indptr on verify metadata, share MTP embed/head after load, and retry K3 mem-fraction restore until the schedule is published. Co-authored-by: Cursor <cursoragent@cursor.com> * [sgl+atom] fix(sglang): keep MiniMax index cache on ATOM FP8 dtype SGLang 0.5.19 MiniMaxSparseKVPool still builds bf16 index-K unless m3_fp8_attn_gemm is on. Align the builder model_dtype for that path and keep the scale-buffer ABI. Co-authored-by: Cursor <cursoragent@cursor.com> * [sgl+atom] fix(sglang): rebind kimi_linear_config on already-imported modules prepare_model patches hybrid_arch after SGLang has already bound kimi_linear_config into kv_cache_configurator and friends. Rebind those local names so the K3 hybrid pool hook actually runs. Co-authored-by: Cursor <cursoragent@cursor.com> * [sgl+atom] Upgrade SGLang to v0.5.20 Bump docker pins from v0.5.19 to v0.5.20. Keep the 0.5.19 plugin bridges; Qwen3.8-Flash is already on main and does not need a transformers bump. Co-authored-by: Cursor <cursoragent@cursor.com> * [sgl+atom] drop Qwen4 recognition shims on SGLang 0.5.20 Upstream 0.5.20 ships qwen4_exp configs, M-RoPE, and processor mapping. Keep Native GDN pad sentinels in their own file until Native GDN reads Hybrid's already-padded buffers. Co-authored-by: Cursor <cursoragent@cursor.com> * [sgl+atom] Adapt 0.5.20 CUDA-graph CLI and ServerArgs lookup. SGLang 0.5.20 treats --cuda-graph-bs as ambiguous and retires get_global_server_args(), which aborted R1 MTP3 and GLM plugin init before any accuracy work ran. Co-authored-by: Cursor <cursoragent@cursor.com> * [sgl+atom] Drop mesh/recipe CLI renames from 0.5.20 fix. Keep only plugin ServerArgs lookup and SGLang CI extra_args that block R1/GLM; leave mesh launch scripts and recipes for a follow-up. Co-authored-by: Cursor <cursoragent@cursor.com> * [sgl+atom] fix(sglang): publish DSV4 proxy _unified_kv ABI for 0.5.20 SGLang reads pool._unified_kv after the ATOM proxy replaces DeepSeekV4TokenToKVPool; keep the flag False and expose get_unified_kv views so Flash/Pro MTP3 no longer AttributeError on CI. Co-authored-by: Cursor <cursoragent@cursor.com> * [sgl+atom] Align K3 mem-fraction and MiniMax index budget with 0.5.20. Mirror upstream aiter reserve predicates (resolved backend + HONOR env), dedupe restore by override source name, wrap MiniMax configure() so cell_size and pool index_dtype share the FP8 model_dtype swap, and split get_sglang_server_args ImportError from live lookup failures. Co-authored-by: Cursor <cursoragent@cursor.com> * [sgl+atom] Fix K3 mem-fraction overrides_log() and HONOR envs lookup. overrides_log is a method on 0.5.20 — iterating the bound method was TypeError'd into the publish-skip path. HONOR must read envs from sglang.srt.environ.envs, not the environ module. Add CPU unit coverage. Co-authored-by: Cursor <cursoragent@cursor.com> * [sgl+atom] Fix K3 mem-fraction unit test expected restore value. Co-authored-by: Cursor <cursoragent@cursor.com> * [sgl+atom] Tighten K3 mem-fraction tests for HONOR and resolved backend. HONOR skip now uses schedule 0.85 so a missed env lookup would override to 1.0. Add coverage that raw aiter with unresolved ""/"auto" does not restore. Co-authored-by: Cursor <cursoragent@cursor.com> * [sgl+atom] Fix Flash decode CUDA graph on SGLang 0.5.20 Skip pin_memory for QSA CpuGpuBuffer during HIP stream capture and register Flash breakable/PLE/replay patches so decode graph capture works on MI308. Co-authored-by: Cursor <cursoragent@cursor.com> * [sgl+atom] fix(sglang): satisfy Ruff on Flash decode graph patches Narrow optional-import handlers and log failures so Pre Checkin reviewdog passes on PR #2280. Co-authored-by: Cursor <cursoragent@cursor.com> * [sgl+atom] style: black-format Flash PLE decode graph patch Co-authored-by: Cursor <cursoragent@cursor.com> * [sgl+atom] Restore CpuGpuBuffer import dropped by the bridge merge. The Flash decode-graph helper still constructs CpuGpuBuffer, but merging Co-authored-by: Cursor <cursoragent@cursor.com> #2385 over that patch left the import behind. * [sgl+atom] Drop the Flash decode-graph PLE refresh that never resolves. The hook imported qwen3_8_flash_next_bridge.refresh_flash_decode_graph_ple, which is not in the tree, so every replay logged a warning and skipped. #2385 already aliases PLE to GDN's static mamba_cache_indices and does not rebuild PLE on replay. Keep the breakable-logits and replay-sync patches. Co-authored-by: Cursor <cursoragent@cursor.com> * [sgl+atom] Drop Flash graph debug patches and non-gating tests. Replay-sync and breakable-logits are off the Flash full-graph path. The K3 CPU mock and the extra DSV4 unified_kv asserts do not gate Pre Checkin; keep the production adapters they were written around. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: xinyuazh <xinyuazh@hjbog-srdc-15.amd.com> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: root <root@hjbog-srdc-15.amd.com>
zhangxinyuanliuhengyu
pushed a commit
that referenced
this pull request
Sep 29, 2026
Move the EP decode asm MoE redirect and the HIP topk=1 Triton tree/verify shims out of atom/model_ops and eagle3_llama_bridge. Ling's #2385 already owns the Flash MTP adapter under plugin/; these 0.5.20 ROCm fixes stay there too. Co-authored-by: Cursor <cursoragent@cursor.com>
zhangxinyuanliuhengyu
added a commit
that referenced
this pull request
Oct 7, 2026
…#2426) * [sgl+atom] Keep ATOM full-attn for Native Qwen4Exp on SGLang 0.5.20. SGLang 0.5.20 swaps hybrid full attention onto QwenSparseAttnBackend, so Native Flash never allocates QSA CUDA-graph buffers and decode capture dies. Leave that backend for non-ATOM Qwen QSA and keep ATOMAttnBackendForSgl for Qwen4Exp. * [sgl+atom] Keep Qwen3.8 Flash EP and MTP working on SGLang 0.5.20. 0.5.20 leaves the speculative draft width unresolved on the raw server args, renames the MTP entry class before ATOM's hook, and the ROCm sgl_kernel tree and greedy-verify kernels fault on the topk=1 chain. Size QSA graph buffers from the resolved spec, load Ling's NextN draft from the text config, keep EP decode on the asm MoE path, and use SGLang's Triton tree kernels on HIP. Co-authored-by: Cursor <cursoragent@cursor.com> * [sgl+atom] Keep Flash EP/MTP ROCm workarounds in the plugin. Move the EP decode asm MoE redirect and the HIP topk=1 Triton tree/verify shims out of atom/model_ops and eagle3_llama_bridge. Ling's #2385 already owns the Flash MTP adapter under plugin/; these 0.5.20 ROCm fixes stay there too. Co-authored-by: Cursor <cursoragent@cursor.com> * [sgl+atom] Keep the HIP Triton tree divert on Qwen4Exp only. v0.5.20 sends every HIP speculative verify through verify_tree_greedy, and R1 MTP already completes on sgl_kernel. Divert tree build and greedy verify only after this process recognizes Qwen4Exp. Co-authored-by: Cursor <cursoragent@cursor.com> * [sgl+atom] Refuse MiniMax mono in the SGLang plugin before the cudagraph check. Co-authored-by: Cursor <cursoragent@cursor.com> #2419 evaluates every mono refusal clause up front, and SGLang leaves cudagraph_mode unset, so MiniMax startup crashes before the plugin-mode clause can refuse. Return that refusal from the plugin without reading cudagraph_mode. * [sgl+atom] Arm the Qwen4Exp HIP divert when the model is prepared. Co-authored-by: Cursor <cursoragent@cursor.com> #2427 wraps is_qwen_qsa later and returns before the inner hook, so the Triton tree/verify flag is set from prepare_model. --------- Co-authored-by: xinyuazh <xinyuazh@hjbog-srdc-15.amd.com> Co-authored-by: Cursor <cursoragent@cursor.com>
zovonoir
added a commit
to zovonoir/ATOM
that referenced
this pull request
Oct 19, 2026
…totype) Qwen3.8-Flash-Next MTP on SGLang-ATOM runs every draft decode step eagerly (ROCm#2385): the plugin skips draft graph capture for Qwen4ExpForCausalLMNextN, citing the [3, N] mRoPE positions that native ATOM's DraftGraph cannot stage. SGLang's EAGLEDraftCudaGraphRunner already carries mrope_positions buffers, so that reason does not hold here. What blocked the graph was the plugin's QSA metadata: the out-of-graph hook filled the target's _DECODE_GRAPH buffers, which TARGET_VERIFY replays from. Behind ATOM_SGLANG_QWEN4_DRAFT_CG=1 (default off, behaviour unchanged): - register.py: stop skipping draft decode graph capture for the Flash drafter. Draft extend stays eager. - qwen4_exp_bridge.py: the draft runner's out-of-graph hook no longer fills the target's buffers. Inside the captured draft forward, QSA metadata is rebuilt into the private _DRAFT_QSA buffers, so each draft step's positions / out_cache_loc are recomputed on replay. Measured on rocm/atom-dev:sglang-v0.5.20-nightly_20261012 (ATOM a0527c9), 2x MI308X, release-note MTP launch (TP2/EP2, ctx 8192, max-running 8, decode graph bs 8), ROCm#2418 harness ISL 1024 / OSL 2048, concurrency 1: | draft steps | eager TPOT / accept | draft graph TPOT / accept | |---|---|---| | 2 | 12.37 ms / 2.39 | 9.16 ms / 2.35 | | 3 | 13.57 ms / 2.61 | 8.19 ms / 2.72 | | 4 | - | 8.69 ms / 2.74 | Steps=2 output throughput, eager -> draft graph: 1024x1 91.6 -> 115.7, 4096x1 84.0 -> 116.9, 1024x8 499.4 -> 600.1, 4096x8 460.6 -> 571.0 tok/s. GSM8K 400 (run_eval chat) 97.75% both ways. A graphed draft step costs about 0.7 ms against about 8 ms eager. Not covered: multimodal requests, long context, decode graph bs > 8, native ATOM. MTP still trails no-MTP TP2/EP1 (6.4 ms TPOT): draft extend is still eager, and EP2 costs the target about 2.3 ms per step.
6 of 8 tasks
zovonoir
added a commit
to zovonoir/ATOM
that referenced
this pull request
Oct 21, 2026
…totype) Qwen3.8-Flash-Next MTP on SGLang-ATOM runs every draft decode step eagerly (ROCm#2385): the plugin skips draft graph capture for Qwen4ExpForCausalLMNextN, citing the [3, N] mRoPE positions that native ATOM's DraftGraph cannot stage. SGLang's EAGLEDraftCudaGraphRunner already carries mrope_positions buffers, so that reason does not hold here. What blocked the graph was the plugin's QSA metadata: the out-of-graph hook filled the target's _DECODE_GRAPH buffers, which TARGET_VERIFY replays from. Behind ATOM_SGLANG_QWEN4_DRAFT_CG=1 (default off, behaviour unchanged): - register.py: stop skipping draft decode graph capture for the Flash drafter. Draft extend stays eager. - qwen4_exp_bridge.py: the draft runner's out-of-graph hook no longer fills the target's buffers. Inside the captured draft forward, QSA metadata is rebuilt into the private _DRAFT_QSA buffers, so each draft step's positions / out_cache_loc are recomputed on replay. Measured on rocm/atom-dev:sglang-v0.5.20-nightly_20261012 (ATOM a0527c9), 2x MI308X, release-note MTP launch (TP2/EP2, ctx 8192, max-running 8, decode graph bs 8), ROCm#2418 harness ISL 1024 / OSL 2048, concurrency 1: | draft steps | eager TPOT / accept | draft graph TPOT / accept | |---|---|---| | 2 | 12.37 ms / 2.39 | 9.16 ms / 2.35 | | 3 | 13.57 ms / 2.61 | 8.19 ms / 2.72 | | 4 | - | 8.69 ms / 2.74 | Steps=2 output throughput, eager -> draft graph: 1024x1 91.6 -> 115.7, 4096x1 84.0 -> 116.9, 1024x8 499.4 -> 600.1, 4096x8 460.6 -> 571.0 tok/s. GSM8K 400 (run_eval chat) 97.75% both ways. A graphed draft step costs about 0.7 ms against about 8 ms eager. Not covered: multimodal requests, long context, decode graph bs > 8, native ATOM. MTP still trails no-MTP TP2/EP1 (6.4 ms TPOT): draft extend is still eager, and EP2 costs the target about 2.3 ms per step.
valarLip
pushed a commit
that referenced
this pull request
Oct 29, 2026
…decode + extend) (#2645) * perf(sglang): capture Qwen3.8-Flash MTP draft decode CUDA graphs (prototype) Qwen3.8-Flash-Next MTP on SGLang-ATOM runs every draft decode step eagerly (#2385): the plugin skips draft graph capture for Qwen4ExpForCausalLMNextN, citing the [3, N] mRoPE positions that native ATOM's DraftGraph cannot stage. SGLang's EAGLEDraftCudaGraphRunner already carries mrope_positions buffers, so that reason does not hold here. What blocked the graph was the plugin's QSA metadata: the out-of-graph hook filled the target's _DECODE_GRAPH buffers, which TARGET_VERIFY replays from. Behind ATOM_SGLANG_QWEN4_DRAFT_CG=1 (default off, behaviour unchanged): - register.py: stop skipping draft decode graph capture for the Flash drafter. Draft extend stays eager. - qwen4_exp_bridge.py: the draft runner's out-of-graph hook no longer fills the target's buffers. Inside the captured draft forward, QSA metadata is rebuilt into the private _DRAFT_QSA buffers, so each draft step's positions / out_cache_loc are recomputed on replay. Measured on rocm/atom-dev:sglang-v0.5.20-nightly_20261012 (ATOM a0527c9), 2x MI308X, release-note MTP launch (TP2/EP2, ctx 8192, max-running 8, decode graph bs 8), #2418 harness ISL 1024 / OSL 2048, concurrency 1: | draft steps | eager TPOT / accept | draft graph TPOT / accept | |---|---|---| | 2 | 12.37 ms / 2.39 | 9.16 ms / 2.35 | | 3 | 13.57 ms / 2.61 | 8.19 ms / 2.72 | | 4 | - | 8.69 ms / 2.74 | Steps=2 output throughput, eager -> draft graph: 1024x1 91.6 -> 115.7, 4096x1 84.0 -> 116.9, 1024x8 499.4 -> 600.1, 4096x8 460.6 -> 571.0 tok/s. GSM8K 400 (run_eval chat) 97.75% both ways. A graphed draft step costs about 0.7 ms against about 8 ms eager. Not covered: multimodal requests, long context, decode graph bs > 8, native ATOM. MTP still trails no-MTP TP2/EP1 (6.4 ms TPOT): draft extend is still eager, and EP2 costs the target about 2.3 ms per step. * perf(sglang): capture the Qwen3.8-Flash MTP draft-extend CUDA graph (prototype) On top of the draft decode graph (ATOM_SGLANG_QWEN4_DRAFT_CG=1), ATOM_SGLANG_QWEN4_DRAFT_EXTEND_CG=1 also graphs the draft extend that runs after every verify. - SGLang only captures draft extend on HIP for aiter multi-step / DSV4 / DSA backends, so the Flash drafter takes the plugin-built EAGLEDraftExtendCudaGraphRunner path that DSV4 / GLM-5.2 use. The QSA metadata is rebuilt into _DRAFT_QSA inside the graph, as for draft decode. The DSV4 / GLM-5.2 long seq_len fill for pad rows is not applied to Flash. - The plugin's EAGLEDraftExtendCudaGraphRunner replay wrapper took only (self, forward_batch); SGLang 0.5.20 calls execute(forward_batch, select_index). Forward extra arguments in every branch. Measured on rocm/atom-dev:sglang-v0.5.20-nightly_20261012 (ATOM a0527c9), 2x MI308X, TP2/EP2. Release-note launch (ctx 8192, max-running 8), ISL 1024 / OSL 2048, conc 1: | steps | decode graph only | decode + extend graph | GSM8K 400 | |---|---|---|---| | 2 | 9.16 ms | 5.90 ms | 97.00% | | 3 | 8.19 ms | 6.01 ms | 97.00% (accept 3.44, same as eager extend) | | 4 | 8.69 ms | 5.17 ms | 97.25% | | 5 | - | 5.02 ms | 97.75% | | 6 | - | 5.88 ms | 96.75% | No MTP, TP2/EP1 on the same image: 6.4 ms. Long-context launch (ctx 132096, max-running 64, decode graph bs 64, mem 0.88), #2418 29-case sweep (ISL 1024-129024, conc 1-32, OSL 2048), 668/668 requests each. Output throughput geomean: | | vs MTP off, TP2/EP1 | vs eager MTP, steps 2 | cases ahead of MTP off | |---|---|---|---| | steps 2 | +14.5% | +43.9% | 25/29 | | steps 4 | +15.4% | +45.0% | 25/29 | Cases behind MTP off: 63488 x 16/32 and 129024 x 8/16, -0.3% to -9.2%. Multimodal (1080p image + ~3.8K-token text, conc 1-16): all answers correct on both launches. * fix(sglang): stage and advance the Flash MTP draft mRoPE; register the draft graph flags SGLang's EAGLE draft decode / draft-extend graph runners capture `mrope_positions` but refresh only the 1-D `positions` on replay, and the buffer is shared by name and shape with other runners. The Flash drafter reads the 3-row positions, so the decode graph ran every draft step at RoPE position 1 and the extend graph read whatever target verify left behind. Stage SGLang's live rows (multimodal offsets included; 1-D positions on all three rows when SGLang computed none) before both replays. EAGLE `draft_forward` also advances only the 1-D positions between draft decode steps, and the runners hand the model a copy of the batch, so the 3-row positions stayed at step 0 (eager and graph). Advance the caller's mRoPE after every Flash draft decode forward; in a graph capture the add is recorded on the graph's buffer. ATOM_SGLANG_QWEN4_DRAFT_CG / _DRAFT_EXTEND_CG are now registered in atom.utils.envs and read there by both the capture gate and the QSA metadata hook, which parsed them differently (`yes` / `on` enabled capture but not the hook's target-buffer isolation). * chore(sglang): drop PROTOTYPE markers from the Flash draft graph comments * perf(sglang): always capture the Flash MTP draft graphs; drop ATOM_SGLANG_QWEN4_DRAFT_CG / _DRAFT_EXTEND_CG With the draft mRoPE staged and advanced, the draft decode and draft-extend graphs match eager drafting in accuracy and acceptance, and eager drafting is host-launch bound (slower than no MTP). Capture both graphs whenever the Flash drafter runs; --disable-cuda-graph still turns them off. * fix(sglang): keep the Flash draft QSA hook Qwen-only; size draft QSA for the graph bucket; order the legacy argmax patch - prepare_qwen4_exp_decode_graph_metadata validates the Qwen4 config before the draft-decode shortcut, so other EAGLE drafters on the ATOM backend keep their normal attention tables. - _ensure_draft_qsa covers the decode graph bucket when --max-running-requests is omitted (32-row default vs. 64-row capture). - On legacy SGLang, install the argmax draft_forward replacement before the mRoPE wrapper so the wrapper composes with it.
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.
Motivation
Enable Qwen3.8-Flash-Next MTP in SGLang-ATOM.
The target and the same-checkpoint 1-layer QSA draft both run Native ATOM
Qwen4Exp/Qwen4ExpMTP. The SGLang plugin only adapts scheduling, QSA pagetables, PLE state, and hyper-connection hidden storage. MTP is scheduled as
SGLang EAGLE with
--speculative-num-steps 2and--speculative-eagle-topk 1(3 draft tokens). Target verify uses CUDA graphs. Draft stays eager because
Flash mRoPE positions are
[3, N], matching Native ATOM.Command
MI308X, TP2 + EP2, BF16 KV, page size 64, no prefix / radix cache.
Checkpoint:
/models/Qwen3.8-Flash-Next-PTPC-FP8.SGLang-ATOM with MTP:
Omit the three
--speculative-*flags to serve without MTP.Native ATOM with MTP, same shape:
Large-output benchmark (ISL 1024, OSL 4096, concurrency 4, 8 prompts, ignore EOS):
GSM8K, 5-shot, 1319 items,
max_gen_toks=4096, stop on<|im_end|>:lm_eval --model local-chat-completions \ --model_args model=/models/Qwen3.8-Flash-Next-PTPC-FP8,base_url=http://127.0.0.1:8000/v1/chat/completions,num_concurrent=8,tokenized_requests=False,trust_remote_code=True \ --tasks gsm8k --num_fewshot 5 \ --gen_kwargs max_gen_toks=4096,until='<|im_end|>' \ --apply_chat_template --confirm_run_unsafe_code \ --output_path ./gsm8kRealWorldQA, 765 items, rule score on the answer text (the Qwen3.5-27B judge was not run):
Performance
Same server shape as above. Random ISL 1024 / OSL 4096, concurrency 4, 8 prompts, ignore EOS. MTP off uses the same benchmark with the speculative flags omitted. Output-token throughput and TPOT are the decode comparison.
MTP helps on this long-output shape. With MTP off, one decode step emits one token, so ITL equals TPOT. With MTP on, a step emits more than one accepted token, so ITL goes up while time per output token goes down.
SGLang-ATOM with MTP is still behind Native ATOM with MTP (10.70 ms vs 8.88 ms, about 13% less output throughput). Verify GPU time matches (about 18.2 ms). The remaining gap is the eager 1-token draft step: its kernels match Native in length, but they are launched on an idle GPU, so host launch latency shows up between kernels. The 3-token draft extend is already packed. Draft CUDA graphs stay off.
ACC
GSM8K flexible-extract / strict-match, 5-shot, 1319 items,
max_gen_toks=4096, stop<|im_end|>, temperature 0:RealWorldQA rule score, 765 items. This counts extracted answers only. The Qwen3.5-27B judge pass was not run.
MTP acceptance
The MTP-on row above (328.12 tok/s, TPOT 10.70 ms) is before the draft QSA
seq_lensfix. That build kept GSM8K answer accuracy, but GSM8K draft acceptance dropped from about 79% to 68%.QSA requires
logical_pos < seq_lens[req]. Target decode sits atseq_lens - 1, so no lift is needed. The second draft step is also 1 token per request (ForwardMode.DECODE), but its position isseq_lens. The packed draft path in_fill_qsa_like_nativeonly lifted whentokens_per_req > 1, so that step left the current token outside the indexer context. The first draft extend (width 3) was lifted. The eager path used by the 79% tree already lifts on any draft forward. ReplaySSM stayed enabled; it was not the change that recovered acceptance.Same GSM8K protocol as the table above, plus
temperature=0,top_k=1,top_p=1. Acceptance is accepted draft tokens / drafted tokens (the bonus token is not in the denominator).accept lenincludes the bonus.The 32-item run is only an acceptance check. It is not a replacement for the 1319-item score.
Remeasured the long-output benchmark after the fix, same shape as the MTP-on row (ISL 1024 / OSL 4096, concurrency 4, 8 prompts, ignore EOS, context 65536, decode graph batch 32):
Mean ITL is unchanged, so the extra lift kernel did not lengthen the step. TPOT improved because each step accepted more draft tokens.