Skip to content

[Bugfix] Export weight-cache IPC tensors separately for each client - #56472

Merged
Isotr0py merged 3 commits into
vllm-project:mainfrom
shaohuaxi:fix/weight-cache-ipc-refcounts
Sep 15, 2026
Merged

Isotr0py merged 3 commits into
vllm-project:mainfrom
shaohuaxi:fix/weight-cache-ipc-refcounts

Conversation

@shaohuaxi

@shaohuaxi shaohuaxi commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Purpose

Starting a copy-mode client can release the weight cache while another engine is still using zero-copy weights. The daemon currently calls reduce_tensor once and sends the same arguments to every client. Those arguments include a reference-count slot for one consumer, so releasing the copy client's temporary IPC tensors can bring the count to zero while the other engine still holds its mappings.

Export the tensors for each get_state response instead. PyTorch then tracks each consumer separately and can keep the underlying allocation alive after the daemon drops its model. Exporting at startup is removed as well, so there is no unused initial reference. The request protocol stays the same.

Related: #51259 fixed export reuse in packed weight transfers; this change covers the separate weight-cache daemon. I checked the related Fast Start PRs, including #56047 and #55468, and found no existing fix for this path.

This change and its tests were developed with AI assistance.

Test Plan

.venv/bin/python -m pytest \
  tests/model_executor/model_loader/test_weight_cache.py \
  -k ipc_cache_release_keeps_live_consumers -v

.venv/bin/pre-commit run --files \
  vllm/model_executor/model_loader/weight_cache/daemon.py \
  tests/model_executor/model_loader/test_weight_cache.py

.venv/bin/pre-commit run mypy-3.12 --hook-stage manual --files \
  vllm/model_executor/model_loader/weight_cache/daemon.py \
  tests/model_executor/model_loader/test_weight_cache.py

The CUDA multiprocessing regression covers copy-only and mixed zero-copy/copy clients. It checks that releasing the daemon cache keeps the producer allocation alive for a live zero-copy consumer, that consumers can still read their tensors, and that the allocation is reclaimed after the last consumer exits.

Test Result

The A10 runs use the target weight-cache and supporting Python files over an existing vLLM CUDA image built from d9fbe526c078 (PyTorch 2.13.0+cu130).

Check Result
Lifecycle regression on 5d49860235f7 2 passed, no skips (52.42s).
Earlier baseline comparison (dbf49dad11e3) 1 passed, 1 failed: the mixed-client case observes 0 allocated bytes where 4096 must remain alive. The retained regression is unchanged from that comparison.
Pre-commit and mypy 3.12 Passed.

Earlier model validation of the unchanged production fix (3c8cafa5ac) produced matching token IDs and text for Qwen/Qwen3.5-0.8B across a copy client's load and shutdown, compared with a disk-loaded baseline.

@shaohuaxi
shaohuaxi requested a review from 22quinn as a code owner September 11, 2026 14:06

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

@mergify mergify Bot added the bug Something isn't working label Sep 11, 2026
@mergify

mergify Bot commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

This pull request has merge conflicts that must be resolved before it can be
merged. Please rebase the PR, @shaohuaxi.

https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork

@mergify mergify Bot added the needs-rebase label Sep 13, 2026
@Isotr0py Isotr0py self-assigned this Sep 13, 2026
@Isotr0py
Isotr0py self-requested a review September 13, 2026 16:19
@shaohuaxi
shaohuaxi force-pushed the fix/weight-cache-ipc-refcounts branch from 0a4a894 to a2ed82c Compare September 14, 2026 01:22
@shaohuaxi

Copy link
Copy Markdown
Contributor Author

Rebased onto the latest main (9f03b510c3) and resolved the conflict, keeping the new get_daemon_model loading path. The test now patches that helper as well. Force-pushed as a single commit, a2ed82c780.

Re-ran the CUDA IPC regression on A10: main gives 1 passed / 1 failed, and the rebased fix gives 2 passed with no GPU skips. Pre-commit and mypy 3.12 also passed.

@mergify mergify Bot removed the needs-rebase label Sep 14, 2026

@Isotr0py Isotr0py left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM, leave a nit

Comment on lines +53 to +55
@pytest.mark.skipif(not torch.cuda.is_available(), reason="CUDA IPC requires a GPU")
@pytest.mark.parametrize("zero_copy_consumer", [False, True], ids=["copy", "mixed"])
def test_ipc_cache_release_keeps_live_consumers(monkeypatch, zero_copy_consumer):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can we use e2e test instead here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added an E2E test using Qwen/Qwen3.5-0.8B and the existing daemon and runner helpers. It keeps a zero-copy engine alive while a copy engine loads, generates, and shuts down, then compares the zero-copy engine's output with a disk-loaded baseline. IPC fallback and prefix caching are disabled.

The E2E also passed without the fix on A10, so I kept the focused allocation-lifetime regression as well; replacing it would lose the test that reproduces the bug. The production fix is unchanged.

Validation on 2fc5add46001: 3 passed (the two ownership cases and the E2E), no skips. Without the fix, the ownership cases give 1 passed / 1 failed: the mixed-client case observes 0 allocated bytes where 4096 must remain alive. Pre-commit and mypy 3.12 also passed. The A10 runs use the target weight-cache and supporting Python files over an existing vLLM CUDA image built from d9fbe526c078.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The E2E also passed without the fix on A10, so I kept the focused allocation-lifetime regression as well; replacing it would lose the test that reproduces the bug. The production fix is unchanged.

I see, if the E2E can't catch the regression, there's no need to keep it then. 🤔

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Removed the added model E2E and its helper changes in 5d49860235. Kept the copy-only and mixed-client allocation-lifetime regression. The production fix is unchanged.

Re-ran the retained tests on A10: 2 passed, no skips. Pre-commit and mypy 3.12 also passed.

@Isotr0py Isotr0py left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM, leave a nit

@shaohuaxi
shaohuaxi force-pushed the fix/weight-cache-ipc-refcounts branch from a2ed82c to 2fc5add Compare September 14, 2026 04:06
@mergify

mergify Bot commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

This pull request has merge conflicts that must be resolved before it can be
merged. Please rebase the PR, @shaohuaxi.

https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork

@mergify mergify Bot added the needs-rebase label Sep 14, 2026
@shaohuaxi
shaohuaxi force-pushed the fix/weight-cache-ipc-refcounts branch from 2fc5add to 3c8cafa Compare September 14, 2026 07:04
@shaohuaxi

Copy link
Copy Markdown
Contributor Author

Rebased onto main dbf49dad11 and pushed a single commit, 3c8cafa5ac. This keeps the multi-node local_rank handling from #55468 and the UUID-based socket lookup from #56669. The focused regression now initializes local_rank as well; the per-client export fix and E2E assertions are unchanged.

Re-ran the A10 checks: the new main gives 1 passed / 1 failed in the focused lifecycle tests, and the rebased fix gives 3 passed with no skips, including the Qwen model E2E. Pre-commit and mypy 3.12 passed. The A10 runs use the target weight-cache and supporting Python files over the existing CUDA image, as described in the PR.

@mergify mergify Bot removed the needs-rebase label Sep 14, 2026
Generate reduction arguments for each get_state transfer instead of
replaying a single export. This lets PyTorch retain the producer allocation
when a copy client releases the daemon cache while a zero-copy client is
still using its weights.

Cover copy-only and mixed clients with a CUDA multiprocessing regression
that checks live mappings and eventual allocation reclamation.

Co-authored-by: Codex <noreply@openai.com>
Signed-off-by: 子华 <huaxi.shx@alibaba-inc.com>
@shaohuaxi
shaohuaxi force-pushed the fix/weight-cache-ipc-refcounts branch from 3c8cafa to 5d49860 Compare September 14, 2026 09:13
@Isotr0py Isotr0py added the ready ONLY add when PR is ready to merge/full CI is needed label Sep 14, 2026
@github-actions

Copy link
Copy Markdown

@shaohuaxi, CI is now available for this PR.

  • /ci run starts upstream CI; /amd-ci run starts AMD CI only.
  • /ci retry retries failed jobs in the CI build for the current PR head. If the current head has no CI build, it starts a new CI build for the current head containing only jobs that failed in the latest earlier CI build for this PR.
  • /amd-ci retry retries failed jobs in AMD CI for the current PR head. Use /amd-ci run when the current head has no AMD CI build.
  • /ci cancel cancels scheduled or running CI builds for this PR branch; /amd-ci cancel does the same for AMD CI only.

Signed-off-by: Isotr0py <Isotr0py@outlook.com>
@Isotr0py
Isotr0py enabled auto-merge (squash) September 14, 2026 09:52
@Isotr0py

Copy link
Copy Markdown
Member

/ci run

@github-actions

Copy link
Copy Markdown

✅ Triggered Buildkite CI #88786 for commit 3a7c7aef3709.

@shaohuaxi

Copy link
Copy Markdown
Contributor Author

/ci retry

@github-actions

Copy link
Copy Markdown

✅ Queued 1 failed job(s) for retry in Buildkite CI #88786.

@Isotr0py
Isotr0py merged commit 567f745 into vllm-project:main Sep 15, 2026
117 checks passed
ItsRoy69 pushed a commit to ItsRoy69/vllm that referenced this pull request Sep 15, 2026
…llm-project#56472)

Signed-off-by: 子华 <huaxi.shx@alibaba-inc.com>
Signed-off-by: Isotr0py <Isotr0py@outlook.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Isotr0py <Isotr0py@outlook.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working ready ONLY add when PR is ready to merge/full CI is needed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants