Repository navigation
[Bugfix] Make the async-output wait bound configurable and default it higher - #6255
hsliuustc0106 merged 4 commits into
Conversation
|
Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits. |
… higher _ASYNC_OUTPUT_TIMEOUT was hardcoded at 30 s. It bounds the wait for one step's background D2H/SHM copy -- a copy that takes milliseconds, but that is queued behind the GPU work for that step, so the wall-clock wait tracks step time. A single-GPU box legitimately runs tens of seconds per step on large shapes, which trips the bound and aborts the request even though the denoise completed; there was no way to raise it short of patching the installed package. A tight bound buys nothing here: worker death and a dead result pump are surfaced by the worker monitor and check_health(), not by this wait. So the only thing it catches is a healthy-but-slow render. Read VLLM_OMNI_ASYNC_OUTPUT_TIMEOUT, defaulting to 600 s to match _DLO_DP_WAVE_TIMEOUT_S in the same subsystem, and name the variable in the timeout log so an operator hitting it knows the knob exists. Read per call rather than at import so widening it does not require a restart. Requested in vllm-project#5793 and vllm-project#5821. Signed-off-by: ivanusto <ivanusto@gmail.com>
975e834 to
2bf8559
Compare
There was a problem hiding this comment.
Pull request overview
This PR makes the diffusion engine’s async-output wait timeout configurable via an environment variable and raises the default to better support long single-GPU denoise step times, preventing healthy-but-slow renders from being aborted by a hardcoded 30s bound.
Changes:
- Replace the hardcoded async-output timeout with
_async_output_timeout()readingVLLM_OMNI_ASYNC_OUTPUT_TIMEOUT(default 600s) and re-read it per call. - Improve timeout logging to mention the environment variable knob.
- Add CPU-only unit tests for default/override/per-call behavior and update the async diffusion output design doc.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
vllm_omni/diffusion/diffusion_engine.py |
Introduces env-var-based timeout resolution and applies it at async and sync wait sites. |
tests/diffusion/test_async_output_timeout.py |
Adds unit tests verifying default value, overrides, and per-call re-reading. |
docs/design/feature/async_diffusion_output.md |
Updates design documentation to reflect the new timeout mechanism and default. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| def _async_output_timeout() -> float: | ||
| """Seconds to wait for one step's background D2H/SHM copy. | ||
|
|
||
| The copy itself finishes in milliseconds, but it is queued behind the GPU | ||
| work for that step, so the wall-clock wait tracks step time — a single-GPU | ||
| box legitimately runs tens of seconds per step on large shapes. A tight | ||
| bound therefore does not catch a hung engine (worker death and a dead | ||
| result pump are surfaced by the worker monitor and ``check_health``); it | ||
| only aborts renders that are still making progress, throwing away the | ||
| denoise that already completed. The default matches | ||
| ``_DLO_DP_WAVE_TIMEOUT_S`` in the same subsystem. | ||
| """ | ||
| return float(os.environ.get(_ASYNC_OUTPUT_TIMEOUT_ENV, _ASYNC_OUTPUT_TIMEOUT_DEFAULT)) |
| logger.error( | ||
| "Timed out after %.0fs waiting for async output; executor state: %s", | ||
| _ASYNC_OUTPUT_TIMEOUT, | ||
| "Timed out after %.0fs waiting for async output (raise %s to allow slower " | ||
| "steps); executor state: %s", | ||
| timeout, | ||
| _ASYNC_OUTPUT_TIMEOUT_ENV, | ||
| describe(output.async_output_id) if describe else "unavailable", |
| def test_value_is_read_per_call(self, monkeypatch): | ||
| """Read at call time rather than import time, so operators are not | ||
| forced to restart the server to widen the bound. | ||
| """ |
|
This PR appears to belong to: docs/design/module/diffusion/index.md. Module owners: @Isotr0py @princepride @SamitHuang @wtomin @ZJY0516 @RuixiangMa @david6666666 @xuechendi @ivanusto, please review your own changes and leave a short self-review comment describing what you checked. PRs without author self-review may not be assigned a reviewer. Please take a look when you have a chance. If you would like an automated review, mention @vllm-omni-review-bot in a comment. |
Three review points: - float() on the env value ran on the request path, so an environment typo would start failing generations at runtime rather than at startup. Parse defensively: a non-numeric or non-positive value is ignored with a warning_once and the default applies. - The timeout log said 'raise VLLM_OMNI_ASYNC_OUTPUT_TIMEOUT', which reads as raising an exception, and printed the bound with %.0f although the knob takes floats. Now 'set ... to a larger value', with %.1f. - A test docstring claimed operators could widen the bound without a restart. Editing the environment of a running process does not generally work that way; the actual benefit is that the value is not frozen in a module constant, which is what the test now says. Raised in review of vllm-project#6255. Signed-off-by: ivanusto <ivanusto@gmail.com>
|
Self-review. What I checked
Review notes addressed in the latest commit
Where I would welcome a second opinion
Not covered No GPU test on this branch. The behaviour was originally observed on a single GB10 running MiniMax-H3 FL2VA at 44–48 s/step (#5821), where the 30 s bound aborted a completed denoise; the change here is confined to how that bound is resolved. |
|
@SamitHuang PTAL |
|
One reference to the old constant survived the update: |
|
On the two questions in the self-review:
One question on the test report: the body shows "133 passed, 1 failed" across the four neighboring suites without naming the failure. Which test failed, and does it also fail on the base commit? Given the self-review's note that an earlier draft of this file polluted |
|
any updates? |
The recipe explained the dropped four-GPU Ref2VA repeats in terms of `_ASYNC_OUTPUT_TIMEOUT`, which this PR removes, leaving the only remaining reference to that name in the tree dangling. Keep the historical fact -- the wait really was a hardcoded 30 s when those numbers were taken -- and name the env var that replaces it, so the recipe stays greppable for anyone hitting the same behaviour. Signed-off-by: ivanusto <ivanusto@gmail.com>
|
Sorry for the delay, and thanks for the careful review. Pushed 62fface, which fixes the stale reference you found.
On your two points, both of which I agree with and neither of which needs a change now:
The two review-bot comments from 08-17 were addressed in the commits before the merge from main, so they may read as outstanding above:
CI was green on the previous head; happy to rebase or squash if you would prefer this as a single commit. |
Answer, with a fresh run rather than the older report. The failure is It fails identically on the base commit. Same container, same command,
Same single failure on both sides, so the delta from this PR is zero. (The counts differ from the 133 in the description because that report was taken at On the state-leakage concern — that was the right thing to check, and it is clean:
Two small things while you are here:
|
…project#6255 Upstream made the async-output wait bound configurable with the same VLLM_OMNI_ASYNC_OUTPUT_TIMEOUT env var (default 600s, lazy parsing, executor-state error message); our stage1-era constant is removed to match upstream exactly. Signed-off-by: zhenggang Lin <115566482+leonail1@users.noreply.github.com>
…project#6255 Upstream made the async-output wait bound configurable with the same VLLM_OMNI_ASYNC_OUTPUT_TIMEOUT env var (default 600s, lazy parsing, executor-state error message); our stage1-era constant is removed to match upstream exactly. Signed-off-by: zhenggang Lin <115566482+leonail1@users.noreply.github.com>
… higher (vllm-project#6255) Signed-off-by: ivanusto <ivanusto@gmail.com> Co-authored-by: Hongsheng Liu <liuhongsheng4@huawei.com> Signed-off-by: AndyZhou952 <jzhoubc@connect.ust.hk>
… higher (vllm-project#6255) Signed-off-by: ivanusto <ivanusto@gmail.com> Co-authored-by: Hongsheng Liu <liuhongsheng4@huawei.com> (cherry picked from commit f09bdcb)
… higher (vllm-project#6255) Signed-off-by: ivanusto <ivanusto@gmail.com> Co-authored-by: Hongsheng Liu <liuhongsheng4@huawei.com>
… higher (vllm-project#6255) Signed-off-by: ivanusto <ivanusto@gmail.com> Co-authored-by: Hongsheng Liu <liuhongsheng4@huawei.com>
Purpose
_ASYNC_OUTPUT_TIMEOUTis hardcoded at 30 s and used at two sites inDiffusionEngine. It bounds the wait for one step's background D2H/SHM copy — a copy that finishes in milliseconds, but that is queued behind the GPU work for that step, so the wall-clock wait tracks step time rather than copy time.On a single GPU, large shapes legitimately run tens of seconds per step, which trips a 30 s bound and aborts the request even though the denoise completed. #5793 reported a 49-step render reaching 49/49 after 31 minutes and being discarded anyway; #5821 reported the same on 44–48 s/step. There is currently no way to raise the bound short of patching the installed package.
A tight bound also buys very little: a genuinely hung engine is surfaced elsewhere — the worker monitor and
check_health()catch worker death,shutdown()settles pending futures, and the pump's dequeue loop breaks on_is_failed. What this wait catches, in practice, is a healthy render that is merely slow.This PR:
VLLM_OMNI_ASYNC_OUTPUT_TIMEOUT, defaulting to 600 s to match_DLO_DP_WAVE_TIMEOUT_Sin the same subsystem (which uses the samefloat(os.environ.get(...))shape);monkeypatchrather than a module reload — an earlier reload-based draft of this test measurably pollutedtests/diffusion/test_diffusion_engine.pywhen the two ran in the same session;warning_onceand the default applies, rather than raisingValueErrormid-generation;docs/design/feature/async_diffusion_output.md, which documented the old 30.0s value.Requested in #5793 (suggested fix 2) and #5821 (suggested fix 3). Note this is only the trigger, not the crash: with #5983 merged the pump now survives the cancellation this timeout causes. #6253 covers the remaining pump-robustness gaps. The three are independent.
Test Plan
New
tests/diffusion/test_async_output_timeout.py(CPU-only, no GPU): default value, integer and float overrides, that the value is re-read per call rather than frozen at import, and that malformed values (non-numeric, empty, zero, negative) fall back to the default.vLLM Version: 0.26.1rc1.dev608+g99a10304d
vLLM-Omni Commit: baba7d1
Test Result
The single failure is
test_move_tensor_tree_moves_nested_cuda_tensors_to_cpu, which needs a CUDA device (RuntimeError: Found no NVIDIA driver on your system) and fails identically on unmodifiedmainin the same container.ruff checkandruff format --checkpass on both changed Python files.