Skip to content

[Feature][SenseNova-U1.5] Resumable prepare phase for step execution - #7730

Open
MrlixiangWE wants to merge 16 commits into
vllm-project:mainfrom
MrlixiangWE:b1-sensenova-step-execution
Open

MrlixiangWE wants to merge 16 commits into
vllm-project:mainfrom
MrlixiangWE:b1-sensenova-step-execution

Conversation

@MrlixiangWE

@MrlixiangWE MrlixiangWE commented Sep 17, 2026 •

Copy link
Copy Markdown
Contributor

Purpose

Part of #7679. SenseNova's think decode currently runs entirely inside prepare_encode(), so step execution cannot return to the scheduler between tokens.

Propose

  1. Add optional SupportsResumablePrepare: prepare_step(state) advances preparation once, and prepare_steps_remaining(state) reports its remaining work.
  2. Run one prepare step per scheduler tick. Once preparation finishes, admit the request to that tick's denoise batch; a prepare phase producing the complete output finishes directly.
  3. Implement the protocol for SenseNova-U1/U1.5 through shared single-token decode loops used by request and step modes. Preserve their distinct stop-token/KV rules. Step mode requires max_num_seqs=1 because the current identity block table holds one sequence.
  4. Sample text using the request seed on the logits device, including generator_device="cpu". With no seed, sampling remains stochastic.
  5. Retirement uses main's release_step_requests ([Bugfix] Finalize step requests before engine idle #8719). SenseNova implements release_step_request(state) ([Core] Introduce a generic cross-attention abstraction with LingBot integration #8859): it drops the step context, including a prepare-phase decode cursor, and clears the flash KV of the denoise caches. Requests that retire inside the prepare phase, and denoise-phase per-request failures, also go through release_step_requests.
  6. Step mode keeps [Model] Avoid redundant SenseNova-U1 denoising synchronizations #8254's hoisting: the CFG step mask, vision grid and noise-scale embedding are built once per request when prepare finishes, and the real _denoise(..., use_cfg) runs per step with no host synchronization. do_true_cfg follows the same CFG mask, so edit requests with cfg_scale=1 and img_cfg_scale!=1 report CFG.
  7. Startup memory profiling is unchanged from main. Step execution is validated on SenseNova-U1.5; U1 and U1-A3B share the pipeline and are marked not verified.

Change summary

Category Files Added Deleted
Production code 4 +733 -164
Tests 4 +1573 -6
Docs / recipes 5 +59 -15
Total 13 +2365 -185

Test Plan

63803da merged with main 15bce34; vLLM 0.32.0, PyTorch 2.13.0+cu130, 2x NVIDIA A800 80GB.

  • pytest tests/entrypoints tests/engine tests/diffusion --ignore=tests/diffusion/models -m 'core_model and cpu', this branch and main.
  • pytest tests/diffusion/models/sensenova_u1 -m 'core_model and cuda' --run-level core_model.
  • SenseNova-U1.5-8B-MoT, BF16, 1024x1024, 25 steps, cfg 4.0, seed 42, max_tokens 64 (48 for sampled text), one request at a time. Three repetitions per process, two processes per arm in opposite order on 1x A800; TP=2 and CFG-parallel 2 on both GPUs.

Test Result

Check This PR main 15bce34
CPU entrypoints/engine/diffusion 10168 passed, 0 failed 10147 passed, 0 failed
CUDA sensenova_u1 16 passed 15 passed
Peak Worker reserved memory, request / step 35,370 / 35,346 MiB 35,390 MiB
Peak host RSS, request / step 7,810 / 6,330 MiB 8,300 MiB

Output digests (MD5 of PNG bytes, SHA-256 prefix of generated text), six repetitions per arm at a0e18c3; at 63803da request and step on 1x A800 give the same digests (three repetitions):

Case main request request step TP=2 request / step CFG-p2 request / step
t2i, think off 7e4ec43 7e4ec43 7e4ec43 e598938 / e598938 7e4ec43 / 7e4ec43
t2i, think on 43531b2 43531b2 43531b2 df3aa27 / df3aa27 43531b2 / 43531b2
edit, think off ea46341 ea46341 ea46341 48cb4a7 / 48cb4a7 ea46341 / ea46341
edit, think on 5c9b35b 5c9b35b 5c9b35b 2db6c3e / 2db6c3e 5c9b35b / 5c9b35b
edit, image cfg 1.5 05b95cc 05b95cc 05b95cc 8591ff8 / 8591ff8 05b95cc / 05b95cc
text2text 0d0cf23 0d0cf23 0d0cf23 0d0cf23 / 0d0cf23 0d0cf23 / 0d0cf23
img2text 10ca5da 10ca5da 10ca5da e8267c9 / e8267c9 10ca5da / 10ca5da
text2text, sampled 5 texts in 6 8fdbc96 8fdbc96 8fdbc96 / 8fdbc96 8fdbc96 / 8fdbc96
text2text, sampled, CPU generator 5 texts in 6 8fdbc96 8fdbc96 8fdbc96 / 8fdbc96 8fdbc96 / 8fdbc96

Median latency of six repetitions at a0e18c3:

Case main request request step
t2i, think off 5.293 s 5.284 s 5.279 s
t2i, think on 9.578 s 9.585 s 9.593 s
edit, think off 5.774 s 5.751 s 5.785 s
edit, think on 13.791 s 13.826 s 13.820 s
edit, image cfg 1.5 8.370 s 8.366 s 8.423 s
text2text 0.901 s 0.898 s 0.897 s
img2text 1.024 s 1.071 s 1.026 s
text2text, sampled 0.686 s 0.686 s 0.692 s
text2text, sampled, CPU generator 0.689 s 0.690 s 0.693 s

@vllm-omni-review-bot

Copy link
Copy Markdown

This PR appears to belong to: docs/design/module/diffusion/offloader.md, docs/design/module/diffusion/index.md.

Module owners: @david6666666 @Isotr0py @princepride

Routing: @david6666666 via module of the changed files, module named in the PR description; @Isotr0py via module of the changed files, module named in the PR description; @princepride via module of the changed files, module named in the PR description

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

@vllm-omni-review-bot

vllm-omni-review-bot commented Sep 17, 2026 •

Copy link
Copy Markdown

Omni ReviewBot: three questions on the performance claim

@MrlixiangWE this PR reads as a performance or value claim:

  • claim: Skip the warm-up and whichever arm runs first is 0.55% to 1.35% faster, so on this machine

Before the full evidence checklist, three short questions:

  1. Bottleneck — what is the current bottleneck, and which profile, trace or per-stage measurement shows it?
  2. Value — what does the change buy the user or the system (latency, throughput, memory, cost), and at which workload?
  3. A/B or ablation — is there a same-workload, same-head/config comparison that isolates each main claim on its own? For stacked optimizations, one number per item rather than a blended delta.

When you answer, the evidence that settles it is: base and head SHA, hardware, model, workload, warm-up and repeat count, mean or percentiles with their spread, and a correctness/quality-equivalence signal; an end-to-end claim also needs stage attribution.

@MrlixiangWE
MrlixiangWE force-pushed the b1-sensenova-step-execution branch from 8e016ed to ae93726 Compare September 17, 2026 13:42
@MrlixiangWE MrlixiangWE changed the title [Feature][SenseNova-U1] Resumable prepare phase for step execution [Feature][SenseNova-U1.5] Resumable prepare phase for step execution Sep 17, 2026
@MrlixiangWE
MrlixiangWE force-pushed the b1-sensenova-step-execution branch 3 times, most recently from 6acc0b0 to 0541926 Compare September 17, 2026 14:00
@MrlixiangWE

Copy link
Copy Markdown
Contributor Author

Three things that could break silently here, and what each is pinned by.

A request whose decode loop is already over when it arrives. prepare_encode and prepare_step both branch on cursor.finished, because a max_tokens of 0 produces a cursor that is finished at construction. test_the_two_modes_produce_the_same_text runs max_tokens 0, 1, 2 and 16 through both execution modes and compares the text.

The two stop rules, which are not interchangeable: </think> takes one more decode step so the token lands in the KV cache and t_idx advances past it, <|im_end|> stops with neither, and the image tokens are positioned from t_idx. test_think_end_takes_one_more_step_and_is_emitted and test_eos_stops_without_a_step_and_is_not_emitted assert the step counts and the resulting t_idx.

A second sequence reaching the model-local paged cache, which would read another request's prefix instead of failing. _check_step_execution_config runs first in __init__ and again in prepare_encode, because streaming_output can turn step_execution on after the pipeline is built; test_construction_rejects_the_configuration_before_it_loads_anything drives the real constructor and test_the_guard_runs_again_on_the_first_request the per-request path.

Removing the runner's three-line prepare hook turns exactly three tests red and leaves the rest green.

@MrlixiangWE MrlixiangWE left a comment

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.

Self-review pass over this head. The first item is a reproduced crash that fails every request in the tick.

Comment thread vllm_omni/diffusion/models/interface.py Resolved
@MrlixiangWE
MrlixiangWE force-pushed the b1-sensenova-step-execution branch from 0541926 to e78e29a Compare September 18, 2026 04:14
@MrlixiangWE

MrlixiangWE commented Sep 18, 2026 •

Copy link
Copy Markdown
Contributor Author

All fixed in 8c971ea.

The crash is gone: the decode that finishes a request inside the prepare phase now runs whichever call ended the phase, so a zero-token text request no longer reaches InputBatch.make_batch without latents. The loop also runs over the scheduler's states rather than over the ones still preparing, so every DiT rank reaches the failure all-reduce the same number of times regardless of pipeline-private state, and a prepare_steps_remaining of 0 now means done. Text sampling takes the request's own generator, so an unseeded request keeps drawing from the global RNG instead of the substituted seed. The feature matrix and the execution-modes page list SenseNova with its max_num_seqs=1 constraint, the profiler targets include the two cache builders and say which entry is step-mode only, and the profile loop fails when it never reached a denoise step.

The image path now runs through the runner — denoise_step → step_scheduler → post_decode with the production Euler update — and the zero-token case is a runner-level test that fails on the previous head with ValueError: All requests must have 'latents' initialized. 169 passed across tests/diffusion/models/sensenova_u1/, test_diffusion_resumable_prepare.py and test_diffusion_step_pipeline.py; 64 passed across the BAGEL, HunyuanImage3 and MiniMax-H3 step-execution suites; ruff clean.

Step execution calls `prepare_encode()` once per request, so SenseNova-U1.5's
think decode runs entirely inside that one call and every other scheduled
request waits on it.

`SupportsResumablePrepare` is an optional companion to `SupportsStepExecution`:
`prepare_step(state)` advances the prepare phase by one step and
`prepare_steps_remaining(state)` reports what is left, with `None` or `0` both
meaning done. `DiffusionModelRunner` runs one prepare step per scheduler tick
for each request still preparing and leaves it out of that tick's denoise batch;
the step that ends the phase puts it back into the same tick. A request whose
prepare phase produces the whole output is decoded and finished there, whichever
call ended the phase — including `prepare_encode()` itself, which is how a
zero-token text request behaves. Every scheduled request reaches the failure
all-reduce the same number of times, so the collective count does not depend on
pipeline-private state.

SenseNovaU1Pipeline implements both. The two decode loops keep their bodies,
including the stop rules that differ between them, and are split into
single-token steps that request mode calls in a loop. Text sampling draws from
the request's own generator, so an unseeded request keeps drawing from the
global RNG. Step execution requires max_num_seqs=1, because `paged_decode.py`
holds one sequence.

Signed-off-by: MrlixiangWE <mrdanaer@gmail.com>
Co-authored-by: zijianc2 <157244773+zijianc2@users.noreply.github.com>
MrlixiangWE and others added 2 commits September 23, 2026 19:30
Co-authored-by: zijianc2 <157244773+zijianc2@users.noreply.github.com>
Signed-off-by: MrlixiangWE <mrdanaer@gmail.com>
Co-authored-by: zijianc2 <157244773+zijianc2@users.noreply.github.com>
Signed-off-by: MrlixiangWE <mrdanaer@gmail.com>
@vllm-omni-review-bot

Copy link
Copy Markdown

Omni ReviewBot: no human activity for 7 days

@MrlixiangWE this pull request has had no human commit, comment or review since 2026-09-26. Please confirm the current plan and next step. The author or a maintainer decides whether to change the PR state.

To keep it moving, any one of these is enough: push an update, reply to the open blocker, or post the current plan and timeline.

MrlixiangWE and others added 2 commits October 4, 2026 16:03
Preserve the component quantization and MoE loading paths while keeping
the resumable prepare protocol and its profiler entry points. Execute
preparation inside the runner forward context so model calls receive the
current configuration before denoising begins.

Cover native context propagation and restoration through all three
prepare stages, and profile both request and step denoising after normal
pipeline construction.

Co-authored-by: zijianc2 <157244773+zijianc2@users.noreply.github.com>
Signed-off-by: MrlixiangWE <mrdanaer@gmail.com>
Retire request-local runner, batch and LoRA state at wave boundaries so
cancelling the last request does not depend on another request arriving.
Clean normal terminals and the complete Worker failure boundary, preserve
startup profiling and keep native KV draining under its existing owner.
Align stage-payload/config types and the SenseNova graph/seed recipe.

Co-authored-by: zijianc2 <157244773+zijianc2@users.noreply.github.com>
Signed-off-by: MrlixiangWE <mrdanaer@gmail.com>
@vllm-omni-review-bot

vllm-omni-review-bot commented Oct 4, 2026 •

Copy link
Copy Markdown

Omni ReviewBot triage note

Resolved as of 63803dab014b: the high-priority or low-quality signal noted on an earlier commit no longer applies.

Copy link
Copy Markdown
Contributor Author

@hsliuustc0106 Ready for review.

@vllm-omni-review-bot

Copy link
Copy Markdown
Omni ReviewBot routing record

Assigned Strict on cursor (cursor-grok-4.6-high) under experiment fleet-strict-cursor-grok46-zcode-glm53flash-5050-c5-z10-20261002.

shihongzhi added a commit to shihongzhi/vllm-omni that referenced this pull request Oct 8, 2026
Review follow-up: the continuous-batching design doc still said the
pipeline rejects max_num_seqs>1 at startup; describe the reviewed
behavior instead — batched denoise waves with serialized think/text
decode, and CFG on/off requests separated at admission. Qualify the
recipe's step-execution measurements: the saved images and timing/
abort numbers predate the restack onto vllm-project#7730, note which contracts the
test suite re-pins on the current stack, and state the waves-group-by-
CFG-switch behavior in the serving section.
shihongzhi added a commit to shihongzhi/vllm-omni that referenced this pull request Oct 9, 2026
Review follow-up: the continuous-batching design doc still said the
pipeline rejects max_num_seqs>1 at startup; describe the reviewed
behavior instead — batched denoise waves with serialized think/text
decode, and CFG on/off requests separated at admission. Qualify the
recipe's step-execution measurements: the saved images and timing/
abort numbers predate the restack onto vllm-project#7730, note which contracts the
test suite re-pins on the current stack, and state the waves-group-by-
CFG-switch behavior in the serving section.

Signed-off-by: shihongzhi <shi65881583@gmail.com>
@vllm-omni-review-bot

Copy link
Copy Markdown
Omni ReviewBot attempt record

Review attempt ended as failed (failed; retrying strict/cursor/cursor-grok-4.6-high in 120s (try 2 of 3)).

@vllm-omni-review-bot

Copy link
Copy Markdown
Omni ReviewBot attempt record

Review attempt ended as failed (failed; retrying strict/cursor/cursor-grok-4.6-high in 600s (try 3 of 3)).

@vllm-omni-review-bot

Copy link
Copy Markdown
Omni ReviewBot attempt record

Review attempt ended as failed (failed; falling back to direct/cursor/auto).

@vllm-omni-review-bot vllm-omni-review-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.

Omni ReviewBot review

Changes since the previous review

  • 0 new inline finding(s); 0 finding(s) below.

CI at e6e9f6f9b47e (2026-10-10T13:37:54.430801+00:00): required check(s) blocking: buildkite/vllm-omni (missing).

Note: The assigned review arm strict/cursor/cursor-grok-4.6-high could not complete this review, so it was produced by the fallback arm direct/cursor/auto. It is excluded from the routing experiment.

Full review analysis

PR description

SenseNova think and text decode no longer run to completion inside one prepare_encode() call. The runner can now advance an optional resumable prepare phase by one token per scheduler tick, then either admit the request to that tick's denoise batch or, for a text request that never sets timesteps, finish it with post_decode(). Request mode and step mode share the same stop rules and seed-aware sampling; step mode still allows only one sequence because the model-local paged cache is unchanged. Finished, failed, and cancelled step requests drop runner state, the cached batch, and Worker LoRA identities at a wave boundary, while native KV drain stays on its existing path.

Change flow

flowchart LR
  A["[EXISTING] Scheduler tick"]:::existing --> B["[CHANGED] Runner prepare and denoise"]:::changed
  B --> C["[NEW] SupportsResumablePrepare"]:::new
  C --> D["[CHANGED] SenseNova one-token decode"]:::changed
  D --> E["[CHANGED] Denoise batch or text finish"]:::changed
  E --> F["[CHANGED] Worker state and LoRA release"]:::changed
  classDef existing fill:#e5e7eb,stroke:#6b7280,color:#111827
  classDef changed fill:#fef3c7,stroke:#d97706,color:#451a03,stroke-width:2px
  classDef new fill:#dcfce7,stroke:#16a34a,color:#052e16,stroke-width:2px
  classDef removed fill:#fee2e2,stroke:#dc2626,color:#450a0a,stroke-width:2px
Loading

🤖 This review was generated by InferMatrix Copilot, an open-source repo-maintenance agent for PR review, CI debugging and issue triage. Try it on your own repo, and ⭐ star it if it helped!

@vllm-omni-review-bot

Copy link
Copy Markdown

Omni ReviewBot: no human activity for 13 days

@MrlixiangWE this pull request has had no human commit, comment or review since 2026-10-04. Please confirm the current plan and next step. The author or a maintainer decides whether to change the PR state.

To keep it moving, any one of these is enough: push an update, reply to the open blocker, or post the current plan and timeline.

MrlixiangWE and others added 8 commits October 21, 2026 13:32
Take main's step-state retirement (vllm-project#8719): the runner, worker and engine
release_step_requests come from main, and this branch's executor method,
duplicate definitions and profile-skip path are dropped, with the tests that
exercised them.

vllm-project#8254 made _denoise take use_cfg and moved the CFG step mask, vision grid
and noise-scale embedding out of the step body. _denoise_one now reads them
from a per-request plan built once by _denoise_plan: before the request-mode
loop, and in _finish_prepare for step execution.

Co-authored-by: zijianc2 <157244773+zijianc2@users.noreply.github.com>
Signed-off-by: MrlixiangWE <mrdanaer@gmail.com>
Main now releases a completed step request and its batch inside
_update_states_after. A one-step profile request therefore leaves
input_batch empty, and the step-mode profile_run, which checked that
attribute to confirm a denoise step ran, raised at startup for every
step-execution pipeline under the paged scheduler. Record that a denoise
batch was built in a latch reset per profile run, and read the latch
instead.

Co-authored-by: zijianc2 <157244773+zijianc2@users.noreply.github.com>
Signed-off-by: MrlixiangWE <mrdanaer@gmail.com>
…etirement hook

Main's runner now calls pipeline.release_step_request(state) for every
retired step state (vllm-project#8859). SenseNova implements it: drop the request's
step context, including a prepare-phase decode cursor, and clear the flash
KV buffers of its denoise caches when an abort or failure retires the
request before post_decode.

Requests that retire inside the resumable prepare phase, after a prepare
failure or with a prepare-only output, now go through
release_step_requests as well, so the pipeline sees the same callback as
for a denoised request.

Co-authored-by: zijianc2 <157244773+zijianc2@users.noreply.github.com>
Signed-off-by: MrlixiangWE <mrdanaer@gmail.com>
Main's check-mark hook rejects a bare platform mark and a CPU mark shared
with an accelerator test. The module-level CPU mark becomes a per-class
mark, and the one CUDA test becomes a module function marked only through
hardware_test.

Co-authored-by: zijianc2 <157244773+zijianc2@users.noreply.github.com>
Signed-off-by: MrlixiangWE <mrdanaer@gmail.com>
Run request mode and step mode over the same schedule with the real
embeddings and the real _denoise, recording only the transformer branches.
Every t2i/it2i CFG configuration takes the same branches at the same steps
in both modes and produces the same image; step mode builds the noise-scale
embedding once and does no host synchronization or grid rebuild inside a
step.

Co-authored-by: zijianc2 <157244773+zijianc2@users.noreply.github.com>
Signed-off-by: MrlixiangWE <mrdanaer@gmail.com>
…se failures through the hook

Startup memory profiling only runs under the paged scheduler, whose profile
request needs Diffusion KV requests that no resumable pipeline produces, so
the prepare-wave loop, its build latch and its verdict could not be reached
by SenseNova and only changed main's behavior. profile_run is main's again.

A per-request failure in the denoise phase now retires through
release_step_requests, so the pipeline's release_step_request runs for it
as it does for completed and aborted requests. The resumable-prepare tests
stub the platform's peak-memory queries so they do not depend on the
host's GPUs. A prepare-loop comment no longer claims rank lockstep.

Co-authored-by: zijianc2 <157244773+zijianc2@users.noreply.github.com>
Signed-off-by: MrlixiangWE <mrdanaer@gmail.com>
Edit requests run CFG when cfg_scale or img_cfg_scale differs from 1, so
cfg_scale > 1 misreported them; set the flag from the plan's CFG steps when
prepare finishes. The real-_denoise test covers an edit with cfg_scale 1
and img_cfg_scale 2. The profiler entry-point test moves next to the other
step-execution tests, and a runner test comment no longer describes an
assertion it does not make.

Co-authored-by: zijianc2 <157244773+zijianc2@users.noreply.github.com>
Signed-off-by: MrlixiangWE <mrdanaer@gmail.com>
Step execution was run on SenseNova-U1.5 only, so SenseNova-U1 and A3B are
marked not verified and the prose names U1.5. The U1 recipe's profiler
stage names follow the current targets and its note reference follows the
renumbered features note; the U1.5 maintainer line is left as on main.

Co-authored-by: zijianc2 <157244773+zijianc2@users.noreply.github.com>
Signed-off-by: MrlixiangWE <mrdanaer@gmail.com>
@MrlixiangWE

Copy link
Copy Markdown
Contributor Author

@hsliuustc0106 i have resove all conflect. could you help in review and merge?

Co-authored-by: zijianc2 <157244773+zijianc2@users.noreply.github.com>
Signed-off-by: MrlixiangWE <mrdanaer@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request high priority high priority issue, needs to be done asap

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants