[Feat] Support step-boundary abort in diffusion (#1769)

Signed-off-by: jader <yjader@foxmail.com>
Signed-off-by: asukaqaq-s <1311722138@qq.com>
Co-authored-by: jader <yjader@foxmail.com>
This commit is contained in:
Wu JIAZHENandjader authored and GitHub committed 2026-04-01 17:25:02 +08:00
1 parent d40840b114
commit 3fd4a4dc27
23 files changed
+1379 -192

No files matched your search

+91 -18
View File
@@ -1,6 +1,9 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
from __future__ import annotations
import queue
import threading
import time
from collections.abc import Iterable
@@ -11,7 +14,11 @@ import PIL.Image
import torch
from vllm.logger import init_logger
from vllm_omni.diffusion.data import DiffusionOutput, OmniDiffusionConfig
from vllm_omni.diffusion.data import (
DiffusionOutput,
DiffusionRequestAbortedError,
OmniDiffusionConfig,
)
from vllm_omni.diffusion.executor.abstract import DiffusionExecutor
from vllm_omni.diffusion.registry import (
DiffusionModelRegistry,
@@ -19,7 +26,9 @@ from vllm_omni.diffusion.registry import (
get_diffusion_pre_process_func,
)
from vllm_omni.diffusion.request import OmniDiffusionRequest
from vllm_omni.diffusion.sched import RequestScheduler, SchedulerInterface
from vllm_omni.diffusion.sched import RequestScheduler, SchedulerInterface, StepScheduler
from vllm_omni.diffusion.sched.interface import DiffusionRequestStatus
from vllm_omni.diffusion.worker.utils import RunnerOutput
from vllm_omni.inputs.data import OmniDiffusionSamplingParams, OmniTextPrompt
from vllm_omni.outputs import OmniRequestOutput
@@ -72,9 +81,14 @@ class DiffusionEngine:
executor_class = DiffusionExecutor.get_class(od_config)
self.executor = executor_class(od_config)
self.scheduler: SchedulerInterface = scheduler or RequestScheduler()
self.step_execution = bool(getattr(od_config, "step_execution", False))
self.scheduler: SchedulerInterface = scheduler or (
StepScheduler() if self.step_execution else RequestScheduler()
)
self.scheduler.initialize(od_config)
self._rpc_lock = threading.Lock()
self._rpc_lock = threading.RLock()
self.abort_queue: queue.Queue[str] = queue.Queue()
self.execute_fn = self.executor.execute_step if self.step_execution else self.executor.execute_request
try:
self._dummy_run()
@@ -98,6 +112,8 @@ class DiffusionEngine:
output = self.add_req_and_wait_for_response(request)
exec_total_time = time.perf_counter() - exec_start_time
if output.aborted:
raise DiffusionRequestAbortedError(output.abort_message or "Diffusion request aborted.")
if output.error:
raise Exception(f"{output.error}")
logger.info("Generation completed successfully.")
@@ -264,7 +280,7 @@ class DiffusionEngine:
def make_engine(
config: OmniDiffusionConfig,
scheduler: SchedulerInterface | None = None,
) -> "DiffusionEngine":
) -> DiffusionEngine:
"""Factory method to create a DiffusionEngine instance.
Args:
@@ -281,8 +297,11 @@ class DiffusionEngine:
# keep scheduling and executing until the target request is finished
while True:
self._process_aborts_queue()
sched_output = self.scheduler.schedule()
if sched_output.is_empty:
if target_sched_req_id in sched_output.finished_req_ids:
return self._finalize_finished_request(target_sched_req_id)
if not self.scheduler.has_requests():
raise RuntimeError("Diffusion scheduler has no runnable requests.")
continue
@@ -292,21 +311,26 @@ class DiffusionEngine:
# vllm_omni/diffusion/sched/base_scheduler.py), so we directly
# take the single scheduled request here.
sched_req_id = sched_output.scheduled_req_ids[0]
req = sched_output.scheduled_new_reqs[0].req
try:
output = self.executor.add_req(req)
runner_output = self.execute_fn(sched_output)
except Exception as exc:
logger.error(
"Execution failed for diffusion request %s",
sched_req_id,
exc_info=True,
logger.error("Execution failed for diffusion request %s", sched_req_id, exc_info=True)
runner_output = RunnerOutput(
req_id=sched_req_id,
step_index=None,
finished=True,
result=DiffusionOutput(error=str(exc)),
)
output = DiffusionOutput(error=str(exc))
finished_req_ids = self.scheduler.update_from_output(sched_output, output)
self._process_aborts_queue()
finished_req_ids = self.scheduler.update_from_output(sched_output, runner_output)
if target_sched_req_id in finished_req_ids:
self.scheduler.pop_request_state(target_sched_req_id)
return output
return self._finalize_finished_request(
target_sched_req_id,
runner_output=runner_output,
missing_result_error="Diffusion execution finished without a final output.",
)
def profile(self, is_start: bool = True, profile_prefix: str | None = None) -> None:
"""Start or stop torch profiling on all diffusion workers.
@@ -437,6 +461,55 @@ class DiffusionEngine:
self.executor.shutdown()
def abort(self, request_id: str | Iterable[str]) -> None:
# TODO implement it
logger.warning("DiffusionEngine abort is not implemented yet")
pass
request_ids = [request_id] if isinstance(request_id, str) else list(request_id)
for req_id in request_ids:
self.abort_queue.put(req_id)
def _process_aborts_queue(self) -> None:
if self.abort_queue.empty():
return
request_ids: list[str] = []
while not self.abort_queue.empty():
ids = self.abort_queue.get_nowait()
request_ids.extend((ids,) if isinstance(ids, str) else ids)
self._abort_requests(request_ids)
def _abort_requests(self, request_ids: str | Iterable[str]) -> None:
request_ids = [request_ids] if isinstance(request_ids, str) else list(request_ids)
sched_req_ids: list[str] = []
for request_id in dict.fromkeys(request_ids):
sched_req_id = self.scheduler.get_sched_req_id(request_id)
if sched_req_id is not None:
sched_req_ids.append(sched_req_id)
for sched_req_id in dict.fromkeys(sched_req_ids):
if self.scheduler.get_request_state(sched_req_id) is not None:
self.scheduler.finish_requests(sched_req_id, DiffusionRequestStatus.FINISHED_ABORTED)
def _finalize_finished_request(
self,
sched_req_id: str,
runner_output: RunnerOutput | None = None,
missing_result_error: str = "Diffusion scheduler finished target request without execution output.",
) -> DiffusionOutput:
state = self.scheduler.get_request_state(sched_req_id)
popped_state = self.scheduler.pop_request_state(sched_req_id)
state = state or popped_state
if state is None:
raise RuntimeError(f"Diffusion scheduler lost state for request {sched_req_id}.")
if state.status == DiffusionRequestStatus.FINISHED_ABORTED:
request_id = state.req.request_ids[0] if state.req.request_ids else sched_req_id
return DiffusionOutput(
aborted=True,
abort_message=f"Request {request_id} aborted.",
)
if runner_output is not None and runner_output.result is not None:
return runner_output.result
return DiffusionOutput(error=missing_result_error)