Skip to content

[Hardware][Ascend] Reclaim denoise-loop allocator blocks before streaming VAE decode - #9313

Open
dongyang1006 wants to merge 1 commit into
vllm-project:mainfrom
dongyang1006:hw-ascend-reclaim-denoise-before-streaming-decode
Open

dongyang1006 wants to merge 1 commit into
vllm-project:mainfrom
dongyang1006:hw-ascend-reclaim-denoise-before-streaming-decode

Conversation

@dongyang1006

@dongyang1006 dongyang1006 commented Oct 23, 2026 •

Copy link
Copy Markdown

1. What outcome do you want to achieve?

Keep stepwise streaming sessions off the physical HBM cap: turn a generation
peak that rides 15 MB under the card limit into one with real headroom, and
stop unreclaimed allocator residency from compounding on long-lived servers.

2. What is the highest-leverage variable for that outcome?

Per-card HBM peak during generation, and post-session allocator residency —
on memory-tight streaming deployments these decide whether a session survives
any transient allocation at all.

3. How will this work move that variable?

Reclaim the denoise loop's cached allocator blocks with
current_omni_platform.empty_cache() at the top of decode_chunk, so the
streaming VAE decode's per-frame buffers allocate into freed space instead of
on top of resident denoise fragments — ~4.2 GiB of headroom recovered at zero
measured cost.

4. Whose customer or user needs does this address, and what are those needs?

Operators running long-lived stepwise streaming servers on memory-tight Ascend
deployments (sequential sessions, shared devices). They need sessions that do
not ride the physical cap and do not leak ~10 GiB of residency per session.

Purpose

WanStreamingDecoder.decode_chunk runs once per committed AR block, right
after the four DMD denoise steps of that block. The denoise loop leaves cached
allocator blocks behind, and the streaming decode then allocates its
per-frame buffers on the same device with those fragments still resident.
Nothing on this path reclaims them: the existing current_omni_platform. empty_cache() call sites in diffusion_worker.py cover the error-cleanup,
paged-KV init, memory-profiling, sleep, and pipeline-hot-swap paths only —
none of them run between a chunk's denoise and its decode.

On memory-tight streaming deployments this is the difference between riding
the physical cap and having real headroom. Measured on 8x Ascend 910B3
(64 GiB HBM per card), lingbot-world-v2-14b stepwise streaming
(lingbot_world_v2_stepwise.yaml, TP2+USP4, 480x832, 117-frame /
11-chunk session, seed 42):

per-card HBM without reclaim with reclaim
peak during generation 65,521 / 65,536 MB (15 MB from the physical cap) 61,273 MB (59.84 GiB)
post-session residency ~63.6 GiB ~52–53 GiB

Sessions complete either way on this workload, but running 15 MB under the
physical cap leaves no room for any transient allocation, and the unreclaimed
residency compounds the risk for long-lived servers (sequential sessions,
shared devices). The reclaim recovers ~4.2 GiB of headroom at zero measured
cost: e2e and inter-chunk latency are unchanged within noise
(64.3–64.5 s / ~6.6 s per chunk over four runs with the reclaim; a single
without-reclaim run was slightly slower at 68.7 s), and outputs stay
byte-identical for a fixed seed (md5-equal MP4s with/without the change).

Design notes:

  • Uses current_omni_platform.empty_cache() — the repo-blessed platform
    abstraction already used by the diffusion worker — instead of
    torch.cuda.empty_cache() (banned by the check-torch-cuda-call
    pre-commit gate) or torch.accelerator.empty_cache() (fails on NPU:
    RuntimeError: Allocator for npu is not a DeviceAllocator with
    torch_npu 2.10).
  • The import is device-guarded and lazy: the module docstring promises that
    only torch is imported so the contract can be exercised without a device,
    a checkpoint, or the distributed VAE stack. Keeping the platform import
    inside the non-CPU branch preserves that property for the device-less
    contract tests (they never take the branch) at a per-chunk call frequency
    where the cached import is negligible.
  • decode_chunk is also the decode entry point for the causvid_wan async
    streaming path (async_stream_decode.py), which interleaves denoise and
    decode on the worker's consumer threads; the reclaim runs there too, on the
    same non-CPU guard.
  • Rebase note: the measurements above were taken on main @
    131a7731a44e2a64feac165580ce99d36beb94ae (file identical to the v0.30.0
    tag). This branch is rebased onto current main, where [Hardware][Ascend] Add opt-in LingBot SP8 output paths #8610 added
    output-format validations at the top of decode_chunk; the reclaim now sits
    ahead of those validations as the method's first statement. The reclaim
    logic itself is unchanged, and
    tests/diffusion/ar_diffusion/test_streaming_decode.py is byte-identical
    between the two revisions.

Test Plan

vLLM Version: 0.30.0 (vllm-ascend 0.19.1rc2.dev, torch 2.10.0 +
torch_npu 2.10.0.post4, CANN 9.1.0)

vLLM-Omni Commit: measured on main @
131a7731a44e2a64feac165580ce99d36beb94ae (= v0.30.0 file state); branch
rebased onto current main — see the rebase note under Purpose.

  1. CPU contract tests (unchanged path):
    python -m pytest tests/diffusion/ar_diffusion/test_streaming_decode.py -q
  2. NPU end-to-end (lingbot-world-v2 stepwise streaming):
    # serve with the stepwise deploy config (TP2+USP4, 8x910B3)
    MODEL=<lingbot-world-v2-14b-causal-fast-diffusers> \
      python -m vllm_omni.entrypoints.cli.main serve "$MODEL" --omni \
        --deploy-config vllm_omni/deploy/lingbot_world_v2_stepwise.yaml --port 8000
    # 33-frame warmup, then 117-frame session (11 chunks) via
    # examples/online_serving/streaming_video_generation/streaming_video_client.py
    # with --image-reference, 832x480, fps 16, seed 42, and a 10-block
    # camera_action_script in --extra-params
  3. HBM sampling during the 117-frame session: npu-smi info polled every 3 s
    (8 cards), run once with and once without the change.

Test Result

  • test_streaming_decode.py: 20 passed (CPU, with and without the change).
  • NPU e2e with the change: 117/117 frames, 11 chunks,
    byte-identical output to the without-reclaim run (same seed, md5-equal).
  • HBM: see the table above (peak 65,521 -> 61,273 MB per card; post-session
    residency ~63.6 -> ~52-53 GiB).
  • Not run: CUDA/ROCm/XPU hardware (no access); the change is device-agnostic
    through the platform abstraction, and the CPU contract tests cover the
    guarded path's syntax/import shape.

AI assistance: the diff, measurements, and this description were drafted with
an AI coding agent (opencode / GLM); I reviewed every line, validated on
8x910B3, and take responsibility for the claims above. Validation commands
and hardware are listed in the Test Plan.

…ming VAE decode

WanStreamingDecoder.decode_chunk runs right after each AR block's denoise steps, and the denoise loop's cached allocator blocks stay resident under the decode's per-frame allocations. No existing empty_cache call site covers this path. Reclaim them through current_omni_platform.empty_cache() behind a non-CPU device guard; the lazy import keeps the module's device-less contract tests free of the platform plugin machinery.

Measured on 8x Ascend 910B3, lingbot-world-v2-14b stepwise streaming (TP2+USP4, 480x832, 117-frame session): per-card HBM peak drops from 65,521/65,536 MB to 61,273 MB, and post-session residency from ~63.6 GiB to ~52-53 GiB. Outputs stay byte-identical for a fixed seed; e2e and inter-chunk latency are unchanged.

Signed-off-by: dongyang1006 <40831215@qq.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ⚠️ Failed 2026-10-23T19:12:04.153507Z
We couldn’t complete this review. Comment @codex review to try again.
e911c2b PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

@vllm-omni-review-bot

Copy link
Copy Markdown

This PR matches CODEOWNERS paths: *****.

Code owners: @Gaohan123 @hsliuustc0106 @ywang96

Routing: @Gaohan123 via CODEOWNERS; @hsliuustc0106 via CODEOWNERS; @ywang96 via CODEOWNERS

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

@hsliuustc0106 hsliuustc0106 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@dongyang1006 — please tie the memory/latency claim to the rebased head e911c2b3647d78e1ba2c1afcc767f70b77678cc5.

  • Supply a matched baseline/head run on the stated 8×910B3 setup, with the complete camera-action input and commands, equal warmups/repetitions, raw per-card memory samples and latency/output results. The current measurements explicitly use 131a773...; one without-reclaim run versus four candidate runs does not establish “zero measured cost.” Distinguish sampled device residency from an allocator peak.
  • Include sequential-session measurements for the residency-compounding claim, and a focused regression that reaches the new non-CPU reclaim branch. The unchanged CPU tests bypass this branch. Acceptance: the intended reclaim executes without changing streamed frame/chunk completeness or fixed-input output, including successive sessions.

This is an evidence gap, not a demonstrated new code defect. Inspection was source-only; I did not run accelerator tests. The disclosed CUDA/ROCm/XPU coverage gap remains.

@hsliuustc0106 hsliuustc0106 added NPU PR related to Ascend NPU diffusion codes related to diffusion models labels Oct 25, 2026 — with Cursor
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

diffusion codes related to diffusion models NPU PR related to Ascend NPU

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants