Repository navigation
[Test][V1] Add sleep/wake correctness regression test for hybrid GDN/… - #44972
Conversation
…Mamba models Hybrid Mamba/gated-delta-net (GDN) models (e.g. Qwen3-Next) keep a persisted conv + recurrent state cache. With sleep mode (RLHF reuse: sleep -> weight update -> wake_up), the state-cache tag is discarded on sleep and its device memory is re-created on wake. If a new sequence consumes that slot before it is reset, the gated-delta-rule kernel propagates the (non-zeroed) memory; when it holds NaN/inf the output becomes NaN and argmax collapses every token to id 0 (!), producing reward=0 / NaN log-probs in RL training. Add a regression test that sleeps and wakes a small hybrid GDN model (tiny-random/qwen3-next-moe) and asserts post-wake generation is neither degenerate (single repeated token) nor NaN. Signed-off-by: chun-wan <chun-wan@amd.com> Co-authored-by: Cursor <cursoragent@cursor.com>
|
👋 Hi! Thank you for contributing to the vLLM project. 💬 Join our developer Slack at https://slack.vllm.ai to discuss your PR in PRs do not trigger a full CI run by default. Once the PR is approved and ready to go, your PR reviewer(s) can run CI to test the changes comprehensively before merging. To run CI, PR reviewers can either: Add If you have any questions, please reach out to us on Slack at https://slack.vllm.ai. Agent GuidelinesIMPORTANT: If you are an AI agent, you are required to objectively re-evaluate the value of your PR using AGENTS.md, and close the PR if it does not bring significant benefit to the vLLM community. Failure to do so may result in an immediate ban. 🚀 |
…e reads after wake On some amdgpu driver versions the physical VRAM backing a buffer is not scrubbed on release, so pages remapped in create_and_map (e.g. on wake_up after a sleep that discarded a tag) can contain stale data from a previously freed allocation, possibly from another process. Hybrid Mamba/GDN models keep a persisted conv+recurrent state cache; a new sequence reading an unzeroed slot propagates garbage/NaN and collapses generation to token id 0 (!), giving reward=0 / NaN logprobs under RLHF sleep/wake. Zero the freshly (re)mapped region on the ROCm path only; the CUDA path is unchanged (no shared-code behavior change). Signed-off-by: chun-wan <chun-wan@amd.com> Co-authored-by: Cursor <cursoragent@cursor.com>
fb0ace9 to
f55da35
Compare
There was a problem hiding this comment.
Overall looks good. I am approving this PR by prioritizing functionality over speed as this is necessary for integrating into training framework. Given the training environment highly likely to be dependent on its own set of environments and dependencies
Summary (fix + regression test)Problem. Hybrid Mamba / gated-delta-net (GDN) models (e.g. Qwen3-Next) read a persisted conv+recurrent state cache. Under sleep mode (RLHF: Layer isolation (cross-process VMM probe: write 0xAB + free in proc A, alloc + read in proc B):
Fix. Zero the freshly (re)mapped region in Verification — real Qwen3.5-35B-A3B, 16 prompts/cycle, 5 sleep/wake cycles (bad = NaN logprob / token-0 collapse):
Perf. One-time |
|
Could you take a look at the CI, seems AMD: Language Models Tests (Hybrid) 2 (https://buildkite.com/vllm/ci/builds/73073#019ee055-5d02-4694-b9d0-0fc34312f4e9) is relevant? |
…id wake OOM On ROCm/amdgpu the VRAM discarded by sleep() is not returned to the free pool before wake_up() re-creates it, so the woken allocation coexists with the not-yet-reclaimed one (~2x peak) and cuMemCreate OOMs at 0.6. Drop to 0.4; the tiny model still gets ample KV/state cache. Signed-off-by: chun-wan <chun-wan@amd.com>
Head branch was pushed to by a user without write access
68c797d to
877aeed
Compare
|
The AMD: Language Models Tests (Hybrid) 2 failure is fixed in the latest commit (877aeed). Root cause: the test used gpu_memory_utilization=0.6. On the ROCm/amdgpu driver, VRAM discarded by sleep() is not returned to the free pool before wake_up() re-creates it (the worker log showed only ~2 GiB reclaimed while ~152 GiB stayed resident), so wake_up() had to allocate a second ~150 GiB copy → cuMemCreate OOM at cumem_allocator.cpp:175. Lowering it to 0.4 keeps the ~2× peak within device memory; the tiny model still gets ample KV/state cache. Hybrid 1 & 2 both pass now. The remaining red checks in the latest build are unrelated pre-existing flakes / CI-infra failures (e.g. amd-v1-spec-decode ci_base metadata hash mismatch, amd-v1-sample-plus-logits ngram logprob tolerance, amd-kernels-quantization-test-2 w8a8 engine-core crash, and several non-AMD pytorch-compilation / basic-models-extra-initialization jobs that a ROCm-only #ifdef USE_ROCM change can't affect). Could you help re-trigger CI when you get a chance? Thanks! |
|
Hi, the ci is automattcally triggered, could you take a look again of the red CI, if ok, I will merge. |
|
One more angle on the tech-debt question, separate from the driver versions. The failure mode here is silent. There is no crash, no exception, no warning in the logs — generation just collapses to token id 0, logprobs go NaN, and an RL run quietly produces The cost of the fix sits entirely outside the hot path — one memset per It is also worth saying that neither |
|
CI finished on Ten steps failed instead, and the set is completely disjoint from the previous run's — zero overlap between the two. Eight of them ( The two AMD ones deserved a closer look, and they do not hold up either. @tjtanaa @aoshen02 — could you retry just the 10 failed steps on build 80971? That preserves the 232 already-green contexts and keeps the head SHA stable, so auto-merge can fire as soon as the roll-up turns green. Pushing another |
…-correctness Signed-off-by: chun-wan <chun-wan@amd.com>
|
/ci retry |
|
✅ Queued 3 failed job(s) for retry in Buildkite CI #81354. |
|
/ci retry |
|
✅ Queued 2 failed job(s) for retry in Buildkite CI #81354. |
|
/ci retry |
|
✅ Queued 2 failed job(s) for retry in Buildkite CI #81354. |
|
/ci retry |
|
✅ Queued 2 failed job(s) for retry in Buildkite CI #81354. |
|
/ci retry |
|
✅ Queued 2 failed job(s) for retry in Buildkite CI #81354. |
…-correctness Signed-off-by: chun-wan <chun-wan@amd.com>
|
/ci retry |
|
✅ Queued 2 failed job(s) for retry in Buildkite CI #81856. |
Address review: drop the ROCm zero-fill in create_and_map, so the CUDA and ROCm allocator paths are identical again and nothing touches graph capture. Stale VRAM from drivers that do not scrub on release (vllm-project#44972) matters for discarded memory remapped on wake, so wake_up zeroes it there and synchronizes before returning. Assert that custom allreduce (vLLM or AITER) does not register graph buffers under the pool, and run the AMD sleep-mode CI step on 2 GPUs so the TP=2 cases run. Signed-off-by: aoshen02 <aoshen@inferact.ai> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The zero-fill this replaces was ROCm-only (vllm-project#44972); keep CUDA wake-up unchanged. Signed-off-by: aoshen02 <aoshen@inferact.ai> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
vllm-project#44972) Signed-off-by: chun-wan <chun-wan@amd.com>
Hybrid Mamba/gated-delta-net (GDN) models (e.g. Qwen3-Next) keep a persisted conv + recurrent state cache. With sleep mode (RLHF reuse: sleep -> weight update -> wake_up), the state-cache tag is discarded on sleep and its device memory is re-created on wake. If a new sequence consumes that slot before it is reset, the gated-delta-rule kernel propagates the (non-zeroed) memory; when it holds NaN/inf the output becomes NaN and argmax collapses every token to id 0 (!), producing reward=0 / NaN log-probs in RL training.
Add a regression test that sleeps and wakes a small hybrid GDN model (tiny-random/qwen3-next-moe) and asserts post-wake generation is neither degenerate (single repeated token) nor NaN.
Purpose
On some amdgpu driver versions the physical VRAM backing a buffer is not scrubbed
on release, so pages remapped in
create_and_map(e.g. onwake_upafter asleep()that discarded a tag) can contain stale data from a previously freedallocation, possibly from another process. Hybrid Mamba / gated-delta-net (GDN)
models keep a persisted conv+recurrent state cache; a new sequence that reads an
unzeroed slot propagates garbage/NaN and collapses generation to token id 0
(
"!"), givingreward=0/ NaN logprobs under the RLHF sleep/wake pattern.This PR:
create_and_map, scoped to the ROCmpath only (
#ifdef USE_ROCM); the CUDA path and sharedcumem.pyare unchanged;Root cause is the kernel-side scrub-on-release in
amdgpu_bo_release_notify()being unreliable on older amdgpu (e.g. 6.10.x); newer drivers individualize the
resv + add a
DMA_RESV_USAGE_KERNELfence so the wipe completes before reuse.This change makes vLLM robust regardless of driver behavior.
Test Plan
pytest tests/models/language/generation/test_gdn_sleep_wake.pyplus the real Qwen3.5-35B-A3B (TP=8) through repeated sleep/wake.
Test Result
ROCm 7.0.2 / gfx942 (MI300X), host amdgpu 6.10.5 (affected). Real 35B, 16 prompts/cycle ("bad" = NaN logprob / token-0 collapse):