Skip to content

[sglang-miles] Colocate RL: flush hybrid state pools before releasing KV cache - #40815

Closed
Zhichenzzz wants to merge 2 commits into
sgl-project:sglang-milesfrom
Zhichenzzz:zhichen/sglang-miles-colocate-hybrid-flush
Closed

Zhichenzzz wants to merge 2 commits into
sgl-project:sglang-milesfrom
Zhichenzzz:zhichen/sglang-miles-colocate-hybrid-flush

Conversation

@Zhichenzzz

@Zhichenzzz Zhichenzzz commented Sep 23, 2026 •

Copy link
Copy Markdown
Collaborator

Motivation

In colocated RL, release_memory_occupation paused (unmapped) the KV cache memory-saver region and only then called flush_cache(). For hybrid models, the pools cleared by flush_cache() live inside that region, and their clear() writes device memory:

  • req_generation, mamba states
  • qwen4_exp PLE state pools: ShortConvPool.conv_state.zero_(), NgramPool.context.fill_()

The write hits unmapped memory and raises a sticky CUDA error 700 (illegal memory access). It surfaces at whatever synchronizes next, so the reported stack names an unrelated op. Plain-KV models never hit this because their clear() is host-side only.

With CUDA_LAUNCH_BLOCKING=1 the fault lands exactly on ple_state_pool.py ShortConvPool.clear(), called from release_memory_occupation -> flush_cache -> HybridReqToTokenPool.clear.

Modifications

  1. release_memory_occupation: flush before pausing the KV region.
  2. Scheduler.flush_cache: skip while the KV region is released. The trainer 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. Returns success so callers treat the cache as clean.

Fixing only (1) is not enough: the second /flush_cache arriving mid-pause faults the same way.

Accuracy / validation

Full-model colocated RL e2e with miles PR radixark/miles#2777 (Qwen3.8-Flash-Next, 8 nodes x 4 GB300, TP2 PP8 EP4 trainer, four TP8 rollout engines, CUDA graph on, --colocate, R3 routing replay, --check-weight-update-equal):

  • Without this change: all four engines die with CUDA error 700 at the first memory release, before any rollout.
  • With this change: 5 rollouts and 5 train steps, weight-update equality check passes, train_rollout_logprob_abs_diff 0.0082 to 0.0129, raw reward 0.47 to 0.75.

CI States

Latest PR Test (Base): ❌ Run #35818880571
Latest PR Test (Extra): ❌ Run #35818880333
Latest PR Test (AMD ROCm 10): ❌ Run #35818880525

… 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.
@Zhichenzzz

Copy link
Copy Markdown
Collaborator Author

Folded into #40821, which carries this fix as its first commit.

@Zhichenzzz Zhichenzzz closed this Sep 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant