Repository navigation
[sglang-miles] Colocated RL for hybrid-state models: flush order and bf16 MoE weight-update layout - #40821
Merged
Zhichenzzz merged 10 commits intoSep 25, 2026
Conversation
… KV cache release_memory_occupation paused (unmapped) the KV cache region and only then called flush_cache(). For hybrid models the pools cleared there live inside that region and clear() writes device memory: req_generation, mamba states, and qwen4_exp's PLE short-conv / n-gram states (ShortConvPool.conv_state.zero_(), NgramPool.context.fill_()). The write hit unmapped memory and raised a sticky CUDA error 700 at the next sync. Plain-KV models never noticed because their clear() is host-side only. - release_memory_occupation: flush before pausing the KV region. - Scheduler.flush_cache: skip while the KV region is released. The trainer side sends /flush_cache again while the engine is offloaded; the pools were already flushed right before the pause, so there is nothing left to clear.
…infer_trtllm weight updates The TRT-LLM bf16 postprocess repacks w13/w2 into block layout ([E, K/128, M, 64] viewed as bf16) for every TRT-LLM MoE runner variant, but the pre-copy shape restore in maybe_restore_flashinfer_trtllm_bf16_weight_shape_for_load only ran for flashinfer_trtllm_routed. On GB300 the auto backend resolves to plain flashinfer_trtllm, so the first RL weight sync copied canonical [*, hidden] expert tensors into blocked params and crashed with 'size of tensor a (64) must match tensor b (4096) at dimension 2'. Guard the restore with self.use_flashinfer_trtllm_moe, the exact flag that gates the repack.
…E runner backends On SM100 the DeepSeek-family override (_deepseek_moe_quant_resolution) resolves moe_runner_backend=auto to flashinfer_trtllm for Glm5Next (and DSv3/GLM-5) with a2a=none, for fp8 and bf16 checkpoints alike. That backend returns a BYPASSED TopK output: routing runs inside the fused kernel and capture_routed_experts_if_allowed never executes, so --enable-return-routed-experts silently ships the zero-initialized host buffer. A miles R3 consumer then replays expert-0-x-topk rows and the training engine's MoE dispatcher dies in alltoall with 'Split sizes doesn't match total dim 0 size'. Add a post-process pass in moe_hook.handle_moe_kernel_config, right after the quant-constraints pass: when enable_return_routed_experts is set and the resolved runner bypasses topk-id materialization (flashinfer_trtllm, experimental_sgl_trtllm, triton_kernel, flashinfer_mxfp4), downgrade to 'auto' for quantization None/fp8 (auto resolves to StandardTopKOutput-consuming runners, so select_experts -> capture runs), and raise for quantizations with no safe fallback.
Zhichenzzz
requested review from
Alisehen,
AniZpZ,
BBuf,
Edwardf0t1,
FlamingoPg,
HaiShaw,
OrangeRedeng,
Ying1123,
b8zhong,
ch-wan,
hnyls2002,
merrymercy,
mmangkad and
xiezhq-hermann
as code owners
September 23, 2026 02:08
…ir constraints The bf16 shape-restore comment narrated how the bug showed up, and the routed-experts guard carried a nine-line preamble naming its downstream consumer plus a long docstring restating the pass ordering. Keep the constraint each line needs; the history is in the fix commits.
…g-miles-glm53-flash-rl
yueming-yuan
approved these changes
Sep 24, 2026
Collaborator
|
[P1] Flush before marking KV memory as offloaded — scheduler.py:5002 |
Collaborator
|
random q: do you think it will be better to directly assert moe_backend not in bypass_topk, and use assert message to ask the user to set --backend auto? (in case the user doesn't want to silently change the backend) |
release_memory_occupation added the tag before calling flush_cache, and flush_cache returns early once the KV tag is set, so the flush before the pause never ran: the radix cache and the allocators kept entries that pointed at KV contents the pause had discarded. Flush first, then tag, then pause. The unit test drives the real Scheduler.flush_cache and release/resume paths: one reset on release, none while paused.
…n-routed-experts Refuse instead of silently switching the runner to auto, so an explicit --moe-runner-backend is never overridden behind the user's back; the error names the fix (a topk-materializing runner such as triton).
tilelang 0.1.14 only pipelines loops with a constant trip count and rejects T.ceildiv(end_max - start_min, block_n) at codegen (Downcast from tirx.Sub to ir.IntImm failed), which broke every Qwen4Exp prefill on images built with that release. The serial loop compiles on 0.1.9 and 0.1.14, gives bitwise identical logits, and costs about 10% on an 8k x 8k prefill (1.15 ms -> 1.26 ms per QSA layer on GB300).
Zhichenzzz
requested review from
Qiaolin-Yu,
hebiao064 and
ispobock
as code owners
September 24, 2026 23:59
The backend choice belongs to the RL launcher (miles pins the triton runner for routing replay), not to server-arg resolution.
ziang-and
pushed a commit
to zianglih/sglang
that referenced
this pull request
Oct 2, 2026
…load; restore bf16 MoE layout (sgl-project#40821) Co-authored-by: Yueming Yuan <yym022502@gmail.com>
nima-ch
added a commit
to kineuro/kvasir
that referenced
this pull request
Oct 13, 2026
…ge (#40) * Thinking written as text: the splitter learns <thinking>, runs on every door, and is set per model The reasoning splitter knew <think> but not <thinking>, ran only on Kvasir's own door, and was set per backend. A model that wrote its reasoning as a <thinking> tag after a swap reached the client with its thinking as the answer. - src/reasoning.ts learns <thinking> (and keeps <think>) and becomes the one shared module: a sha256 stamp, scripts/share-reasoning.mjs to stamp and copy it to the assistant and the desk, and a test that checks the stamp. - src/split-doors.ts reads reasoning apart on the pass-through doors: chat completions (reasoning_content), Anthropic's messages (a thinking block) and responses (a reasoning item), whole and streamed. An answer with no marker passes byte for byte. Legacy completions are left as they came. - inlineReasoning is set per model (a card's model, a card, a held backend's model), over the backend's setting, which stays the default. - test/thinking-doors.test.ts: a request after a swap on each door gives the reasoning apart from the answer; a model set to off keeps its text. * A card whose models sleep: release and resume, and the sleep-and-wake fault never reaches a request Record 55, B6; spec section 14 and slice C2. A Docker card with "sleep": "release" swaps warm: the model that leaves the card releases its GPU memory with its weights kept in the host's memory (/release_memory_occupation on its SGLang server), and resumes them when it is asked for again (/resume_memory_occupation). - A release that does not answer, or whose server exits after it (SGLang 0.5.20 and 0.5.21 on hybrid models, CUDA error 700), stops the container instead; a woken model that does not answer its health in time is started again cold. The fault costs a cold swap, never a failed request. - A sleeping server is never asked for its health, a generation on SGLang. - Which models sleep is kept beside the database, so a Kvasir started again knows them; at start the card keeps an awake model before a sleeping default. - "sleep": "stop" stays the default; a llama.cpp router's card takes only stop. - test/sleep.test.ts: three server images (a working memory saver, one that crashes at the release, one that dies after waking), each answering every request after a sleep and a wake. - scripts/check-sleep-image.sh: SGLang's own flush-order test run inside a candidate image; it fails on 0.5.21 and passes on 0.5.21 with sgl-project/sglang#40821 applied.
nv-hwoo
pushed a commit
to nv-hwoo/sglang
that referenced
this pull request
Oct 20, 2026
…load; restore bf16 MoE layout (sgl-project#40821) Co-authored-by: Yueming Yuan <yym022502@gmail.com>
nanjiangwill
pushed a commit
to modal-projects/sglang
that referenced
this pull request
Oct 21, 2026
…load; restore bf16 MoE layout (sgl-project#40821) Co-authored-by: Yueming Yuan <yym022502@gmail.com> (cherry picked from commit d3c23d2) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VDwTQn4gGFgVhzGXFs4aJx
Rockdu
pushed a commit
that referenced
this pull request
Oct 30, 2026
…load; restore bf16 MoE layout (#40821) Co-authored-by: Yueming Yuan <yym022502@gmail.com>
Rockdu
pushed a commit
that referenced
this pull request
Oct 30, 2026
…load; restore bf16 MoE layout (#40821) Co-authored-by: Yueming Yuan <yym022502@gmail.com>
Rockdu
pushed a commit
that referenced
this pull request
Oct 31, 2026
…load; restore bf16 MoE layout (#40821) Co-authored-by: Yueming Yuan <yym022502@gmail.com>
Rockdu
pushed a commit
that referenced
this pull request
Oct 31, 2026
…load; restore bf16 MoE layout (#40821) Co-authored-by: Yueming Yuan <yym022502@gmail.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.
Fixes needed for colocated RL on hybrid-state models (Qwen3.8-Flash-Next, GLM-5.3-Flash) on current
sglang-miles. Supersedes #40815, which is folded in here as the first commit.Motivation
release_memory_occupationpaused (unmapped) the KV cache memory-saver region and only then calledflush_cache(). The hybrid pools cleared there (mamba states, qwen4_exp PLEShortConvPool/NgramPool, KDA state) live inside that region and theirclear()writes device memory, so the write hits unmapped memory. WithCUDA_LAUNCH_BLOCKING=1the fault lands onShortConvPool.clear()viarelease_memory_occupation -> flush_cache -> HybridReqToTokenPool.clear. The trainer's later/flush_cachewhile the engine is offloaded faults the same way.flashinfer_trtllm. The TRT-LLM bf16 postprocess repacksw13/w2into block layout for every TRT-LLM MoE runner variant, butmaybe_restore_flashinfer_trtllm_bf16_weight_shape_for_loadonly restored the canonical shape forflashinfer_trtllm_routed. On GB300 the auto backend resolves to plainflashinfer_trtllm, so the first weight sync failed withsize of tensor a (64) must match tensor b (4096) at dimension 2.Modifications
weight_updater.py: flush before tagging the KV region as offloaded and pausing it (the tag is what makes the later flush a no-op).Scheduler.flush_cache: return success without clearing while the KV region is released (the pools were flushed right before the pause).unquant.py: gate the shape restore onself.use_flashinfer_trtllm_moe, the same flag that gates the repack.qsa/mqa.py: the prefill indexer walks its key tiles with a serial loop. tilelang 0.1.14 only pipelines constant trip counts and rejectedT.ceildiv(end_max - start_min, block_n)at codegen (Downcast from tirx.Sub to ir.IntImm failed), which broke every Qwen4Exp prefill on images built with that release (the miles CI image). Logits are bitwise identical on 0.1.9; an 8k x 8k prefill costs about 10% more per QSA layer on GB300.Validation
Full-model colocated RL e2e, 8 nodes x 4 GB300, latest
radixark/miles:dev,--colocate, R3 routing replay, CUDA graph on:train_rollout_logprob_abs_diff0.0083 to 0.0131, raw reward 0.47 to 0.75.train_rollout_logprob_abs_diff0.0085 / 0.0098 / 0.0087, raw reward 0.50 to 0.72; routed experts were captured with the triton runner, which the miles launcher now pins for routing replay (the resolver guard was dropped from this PR).CI States
Latest PR Test (Base): ❌ Run #36084620812
Latest PR Test (Extra): ❌ Run #36084620581
Latest PR Test (AMD ROCm 10): ❌ Run #36084620803