Skip to content

[Bugfix] Release worker RPC payload before next dequeue - #51979

Open
shipiyouniao wants to merge 1 commit into
vllm-project:mainfrom
shipiyouniao:fix/worker-rpc-arg-lifetime
Open

[Bugfix] Release worker RPC payload before next dequeue#51979
shipiyouniao wants to merge 1 commit into
vllm-project:mainfrom
shipiyouniao:fix/worker-rpc-arg-lifetime

Conversation

@shipiyouniao

Copy link
Copy Markdown

Summary

Fixes #43639 by executing each worker RPC in a separate stack frame. This
releases the deserialized request arguments and local output reference before
the next MessageQueue.dequeue() deserializes another request, without adding
a full gc.collect() to the RPC hot path.

The existing exception-to-worker-response behavior is preserved.

Why this approach

The previous loop retains method, args, kwargs, and output while the
next request is being dequeued. For RPCs containing CPU tensors, that makes two
deserialized payloads overlap in lifetime and raises the transient CPU memory
high-water mark.

Moving one RPC iteration into _execute_worker_rpc() gives those references a
shorter, deterministic lifetime. A weak-reference regression test verifies
that the first payload has been released at the instant the second dequeue
begins.

This does not duplicate an open PR. I checked both 43639 in:body and worker
RPC/deserialization memory-leak keywords. The earlier PR #45248 is closed and
used per-request gc.collect(), while this change avoids forcing global GC in
the hot path and uses deterministic lifetime coverage instead of an RSS
threshold.

Tests

pytest tests/v1/executor/test_multiproc_executor.py
2 passed

ruff check vllm/v1/executor/multiproc_executor.py \
  tests/v1/executor/test_multiproc_executor.py
All checks passed

ruff format --check vllm/v1/executor/multiproc_executor.py \
  tests/v1/executor/test_multiproc_executor.py
2 files already formatted

mypy --follow-imports=skip --ignore-missing-imports \
  vllm/v1/executor/multiproc_executor.py \
  tests/v1/executor/test_multiproc_executor.py
Success: no issues found in 2 source files

The lifetime comparison also reports:

unpatched: payload alive when the next dequeue starts = true
patched:   payload alive when the next dequeue starts = false

T4 performance A/B

I ran an alternating baseline -> patched -> baseline -> patched offline
throughput comparison on one NVIDIA Tesla T4. Both variants used the same
container, PyTorch/CUDA stack, FP16 Qwen3-MoE-derived 0.8B test model, random
seed, and benchmark arguments. The only changed mounted file was
multiproc_executor.py.

Configuration:

vLLM 0.18.0 performance container
1x NVIDIA Tesla T4 (15 GiB)
64 requests per measured run
64 input tokens + 32 output tokens per request
FP16, TP=1, max_num_seqs=64
TRITON_ATTN, eager mode, seed=1234
Run Baseline total tok/s Patched total tok/s Paired delta
1 118.226 118.116 -0.093%
2 118.203 118.327 +0.105%
Mean 118.215 118.222 +0.006%

Mean inference time was 51.973 s for baseline and 51.970 s for patched over
6,144 tokens per run. No throughput regression was observed; the paired
variation is approximately +/-0.1%.

For transparency, this was a controlled performance-only A/B in an available
vLLM 0.18.0 CUDA image, with the same method-level change transplanted onto
that code path. The correctness and lifetime tests above were run against this
PR's latest-main checkout. No model evaluation is applicable because the
change does not affect model outputs or numerical execution.

AI assistance

OpenAI Codex assisted with investigation, implementation, and test drafting.
I reviewed the resulting change and the validation described above.

Execute each worker RPC in a separate stack frame so deserialized arguments
and outputs are released before the next message is deserialized. Preserve
exception handling behavior and add deterministic lifetime regression coverage.

Fixes vllm-project#43639

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: 石皮幼鸟 <2960474346@qq.com>
Copilot AI lite review requested due to automatic review settings August 12, 2026 10:45
@shipiyouniao
shipiyouniao requested a review from njhill as a code owner August 12, 2026 10:45

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

@github-actions

Copy link
Copy Markdown

👋 Hi! Thank you for contributing to the vLLM project.

💬 Join our developer Slack at https://slack.vllm.ai to discuss your PR in #pr-reviews, coordinate on features in #feat- channels, or join special interest groups in #sig- channels.

PRs do not trigger a full CI run by default. Reviewers with write access and configured trusted contributors can comment /ci run whenever CI signals are needed.

Once the PR is approved or has the ready label, the PR author can also use /ci run, /ci retry, or /ci cancel. New commits do not start CI automatically.

If you have any questions, please reach out to us on Slack at https://slack.vllm.ai.

Agent Guidelines

IMPORTANT: 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.

🚀

@mergify mergify Bot added the bug Something isn't working label Aug 12, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses transient CPU memory high-water issues in the worker RPC deserialization path by ensuring each RPC is executed in its own stack frame, allowing request arguments and outputs to be released before the next MessageQueue.dequeue() call.

Changes:

  • Refactors WorkerProc.worker_busy_loop() to delegate per-RPC execution into a new _execute_worker_rpc() helper to shorten the lifetime of deserialized payload references.
  • Adds regression tests that verify the prior RPC payload is released before the next dequeue begins, and that exception-to-response behavior is preserved.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
vllm/v1/executor/multiproc_executor.py Executes each worker RPC in a separate frame to reduce overlap in payload lifetimes between dequeues.
tests/v1/executor/test_multiproc_executor.py Adds weakref-based lifetime regression coverage plus an exception-handling behavior test for _execute_worker_rpc().

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +1039 to +1040
# exception might not be serializable, so we convert it to
# string, only for logging purpose.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: OOM killed caused by possible CPU memory leak in vLLM Worker RPC Broadcast Deserialization Path

2 participants