2026-02-25 08:09:11 -08:00
|
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
|
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
|
|
|
|
|
|
|
|
|
from contextlib import contextmanager
|
|
|
|
|
from types import SimpleNamespace
|
|
|
|
|
|
|
|
|
|
import pytest
|
|
|
|
|
import torch
|
|
|
|
|
|
|
|
|
|
import vllm_omni.diffusion.worker.diffusion_model_runner as model_runner_module
|
2026-04-20 14:23:42 +08:00
|
|
|
from tests.helpers.mark import hardware_test
|
2026-02-25 08:09:11 -08:00
|
|
|
from vllm_omni.diffusion.worker.diffusion_model_runner import DiffusionModelRunner
|
|
|
|
|
|
2026-04-09 10:31:21 +08:00
|
|
|
pytestmark = [pytest.mark.diffusion]
|
2026-02-25 08:09:11 -08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
@contextmanager
|
|
|
|
|
def _noop_forward_context(*args, **kwargs):
|
|
|
|
|
del args, kwargs
|
|
|
|
|
yield
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class _DummyPipeline:
|
|
|
|
|
def __init__(self, output):
|
|
|
|
|
self._output = output
|
|
|
|
|
self.forward_calls = 0
|
|
|
|
|
|
|
|
|
|
def forward(self, req):
|
|
|
|
|
del req
|
|
|
|
|
self.forward_calls += 1
|
|
|
|
|
return self._output
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _make_request(skip_cache_refresh: bool = True):
|
|
|
|
|
sampling_params = SimpleNamespace(
|
|
|
|
|
generator=None,
|
|
|
|
|
seed=None,
|
|
|
|
|
generator_device=None,
|
|
|
|
|
num_inference_steps=4,
|
|
|
|
|
)
|
|
|
|
|
return SimpleNamespace(
|
|
|
|
|
prompts=["a prompt"],
|
|
|
|
|
sampling_params=sampling_params,
|
|
|
|
|
skip_cache_refresh=skip_cache_refresh,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _make_runner(cache_backend, cache_backend_name: str, enable_cache_dit_summary: bool = True):
|
|
|
|
|
runner = object.__new__(DiffusionModelRunner)
|
|
|
|
|
runner.vllm_config = object()
|
|
|
|
|
runner.device = torch.device("cpu")
|
|
|
|
|
runner.pipeline = _DummyPipeline(output=SimpleNamespace(output="ok"))
|
|
|
|
|
runner.cache_backend = cache_backend
|
|
|
|
|
runner.offload_backend = None
|
2026-05-29 15:36:03 +08:00
|
|
|
runner.prompt_embed_cache = None
|
2026-02-25 08:09:11 -08:00
|
|
|
runner.od_config = SimpleNamespace(
|
|
|
|
|
cache_backend=cache_backend_name,
|
|
|
|
|
enable_cache_dit_summary=enable_cache_dit_summary,
|
2026-02-26 21:31:10 +08:00
|
|
|
parallel_config=SimpleNamespace(use_hsdp=False),
|
2026-02-25 08:09:11 -08:00
|
|
|
)
|
2026-03-02 13:06:28 +08:00
|
|
|
runner.kv_transfer_manager = SimpleNamespace(
|
|
|
|
|
receive_kv_cache=lambda req, target_device=None: None,
|
|
|
|
|
receive_multi_kv_cache=lambda req, cfg_kv_collect_func=None, target_device=None: None,
|
2026-03-23 21:52:50 +08:00
|
|
|
receive_multi_kv_cache_distributed=lambda req, cfg_kv_collect_func=None, target_device=None: None,
|
2026-03-02 13:06:28 +08:00
|
|
|
)
|
2026-02-25 08:09:11 -08:00
|
|
|
return runner
|
|
|
|
|
|
|
|
|
|
|
2026-04-09 10:31:21 +08:00
|
|
|
@pytest.mark.core_model
|
|
|
|
|
@hardware_test(res={"cuda": "L4"}, num_cards=1)
|
2026-02-25 08:09:11 -08:00
|
|
|
def test_execute_model_skips_cache_summary_without_active_cache_backend(monkeypatch):
|
|
|
|
|
"""Guard cache diagnostics with runtime backend state to avoid stale-config crashes."""
|
|
|
|
|
runner = _make_runner(cache_backend=None, cache_backend_name="cache_dit")
|
|
|
|
|
req = _make_request(skip_cache_refresh=True)
|
|
|
|
|
|
|
|
|
|
cache_summary_calls = []
|
|
|
|
|
|
|
|
|
|
monkeypatch.setattr(model_runner_module, "set_forward_context", _noop_forward_context)
|
|
|
|
|
monkeypatch.setattr(
|
|
|
|
|
model_runner_module,
|
|
|
|
|
"cache_summary",
|
|
|
|
|
lambda pipeline, details: cache_summary_calls.append((pipeline, details)),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
output = DiffusionModelRunner.execute_model(runner, req)
|
|
|
|
|
|
|
|
|
|
assert output.output == "ok"
|
|
|
|
|
assert cache_summary_calls == []
|
|
|
|
|
|
|
|
|
|
|
2026-04-09 10:31:21 +08:00
|
|
|
@pytest.mark.core_model
|
|
|
|
|
@hardware_test(res={"cuda": "L4"}, num_cards=1)
|
2026-02-25 08:09:11 -08:00
|
|
|
def test_execute_model_emits_cache_summary_with_active_cache_dit_backend(monkeypatch):
|
|
|
|
|
class _EnabledCacheBackend:
|
|
|
|
|
def is_enabled(self):
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
runner = _make_runner(cache_backend=_EnabledCacheBackend(), cache_backend_name="cache_dit")
|
|
|
|
|
req = _make_request(skip_cache_refresh=True)
|
|
|
|
|
|
|
|
|
|
cache_summary_calls = []
|
|
|
|
|
|
|
|
|
|
monkeypatch.setattr(model_runner_module, "set_forward_context", _noop_forward_context)
|
|
|
|
|
monkeypatch.setattr(
|
|
|
|
|
model_runner_module,
|
|
|
|
|
"cache_summary",
|
|
|
|
|
lambda pipeline, details: cache_summary_calls.append((pipeline, details)),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
output = DiffusionModelRunner.execute_model(runner, req)
|
|
|
|
|
|
|
|
|
|
assert output.output == "ok"
|
|
|
|
|
assert cache_summary_calls == [(runner.pipeline, True)]
|
|
|
|
|
|
|
|
|
|
|
2026-04-09 10:31:21 +08:00
|
|
|
@pytest.mark.core_model
|
|
|
|
|
@pytest.mark.cpu
|
2026-02-25 08:09:11 -08:00
|
|
|
def test_load_model_clears_cache_backend_for_unsupported_pipeline(monkeypatch):
|
|
|
|
|
class _DummyLoader:
|
2026-03-02 22:53:25 +08:00
|
|
|
def __init__(self, load_config, od_config=None):
|
|
|
|
|
del load_config, od_config
|
2026-02-25 08:09:11 -08:00
|
|
|
|
|
|
|
|
def load_model(self, **kwargs):
|
|
|
|
|
del kwargs
|
|
|
|
|
return SimpleNamespace(transformer=torch.nn.Identity())
|
|
|
|
|
|
|
|
|
|
class _DummyMemoryProfiler:
|
|
|
|
|
consumed_memory = 0
|
|
|
|
|
|
|
|
|
|
def __enter__(self):
|
|
|
|
|
return self
|
|
|
|
|
|
|
|
|
|
def __exit__(self, exc_type, exc, tb):
|
|
|
|
|
del exc_type, exc, tb
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
class _DummyCacheBackend:
|
|
|
|
|
def __init__(self):
|
|
|
|
|
self.enabled = False
|
|
|
|
|
|
|
|
|
|
def enable(self, pipeline):
|
|
|
|
|
del pipeline
|
|
|
|
|
self.enabled = True
|
|
|
|
|
|
|
|
|
|
dummy_cache_backend = _DummyCacheBackend()
|
|
|
|
|
|
|
|
|
|
runner = object.__new__(DiffusionModelRunner)
|
|
|
|
|
runner.vllm_config = object()
|
|
|
|
|
runner.device = torch.device("cpu")
|
|
|
|
|
runner.pipeline = None
|
|
|
|
|
runner.cache_backend = None
|
|
|
|
|
runner.offload_backend = None
|
|
|
|
|
runner.od_config = SimpleNamespace(
|
|
|
|
|
enable_cpu_offload=False,
|
|
|
|
|
enable_layerwise_offload=False,
|
|
|
|
|
cache_backend="cache_dit",
|
|
|
|
|
cache_config={},
|
|
|
|
|
model_class_name="NextStep11Pipeline",
|
|
|
|
|
enforce_eager=True,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
monkeypatch.setattr(model_runner_module, "LoadConfig", lambda: object())
|
|
|
|
|
monkeypatch.setattr(model_runner_module, "DiffusersPipelineLoader", _DummyLoader)
|
|
|
|
|
monkeypatch.setattr(model_runner_module, "DeviceMemoryProfiler", _DummyMemoryProfiler)
|
|
|
|
|
monkeypatch.setattr(model_runner_module, "get_offload_backend", lambda od_config, device: None)
|
|
|
|
|
monkeypatch.setattr(
|
|
|
|
|
model_runner_module, "get_cache_backend", lambda cache_backend, cache_config: dummy_cache_backend
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
DiffusionModelRunner.load_model(runner)
|
|
|
|
|
|
|
|
|
|
assert runner.cache_backend is None
|
|
|
|
|
assert runner.od_config.cache_backend is None
|
|
|
|
|
assert dummy_cache_backend.enabled is False
|
2026-05-06 21:11:35 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.core_model
|
|
|
|
|
@pytest.mark.cpu
|
|
|
|
|
def test_set_forward_context_enters_vllm_config_contexts(monkeypatch):
|
|
|
|
|
"""Ensure `with set_forward_context(...):` enters vllm's context managers internally and calls desired vllm functions."""
|
|
|
|
|
import vllm.config.vllm as vllm_config_module
|
|
|
|
|
import vllm.ir
|
|
|
|
|
from vllm.config import CompilationConfig, DeviceConfig, VllmConfig
|
|
|
|
|
|
|
|
|
|
from vllm_omni.diffusion.forward_context import (
|
|
|
|
|
get_forward_context,
|
|
|
|
|
is_forward_context_available,
|
|
|
|
|
set_forward_context,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
vllm_config = VllmConfig(
|
|
|
|
|
device_config=DeviceConfig(device="cpu"),
|
|
|
|
|
compilation_config=CompilationConfig(),
|
|
|
|
|
)
|
|
|
|
|
calls = []
|
|
|
|
|
|
|
|
|
|
@contextmanager
|
|
|
|
|
def _set_current_vllm_config(cfg):
|
|
|
|
|
calls.append(("set_current_vllm_config", cfg))
|
|
|
|
|
yield
|
|
|
|
|
calls.append(("set_current_vllm_config_exit", cfg))
|
|
|
|
|
|
|
|
|
|
@contextmanager
|
|
|
|
|
def _set_priority(*args, **kwargs):
|
|
|
|
|
del args, kwargs
|
|
|
|
|
calls.append(("ir_op_priority", None))
|
|
|
|
|
yield
|
|
|
|
|
calls.append(("ir_op_priority_exit", None))
|
|
|
|
|
|
|
|
|
|
@contextmanager
|
|
|
|
|
def _enable_torch_wrap(flag):
|
|
|
|
|
calls.append(("enable_torch_wrap", flag))
|
|
|
|
|
yield
|
|
|
|
|
calls.append(("enable_torch_wrap_exit", flag))
|
|
|
|
|
|
|
|
|
|
monkeypatch.setattr(vllm_config_module, "set_current_vllm_config", _set_current_vllm_config)
|
|
|
|
|
monkeypatch.setattr(vllm_config.kernel_config.ir_op_priority, "set_priority", _set_priority)
|
|
|
|
|
monkeypatch.setattr(vllm.ir, "enable_torch_wrap", _enable_torch_wrap)
|
|
|
|
|
|
|
|
|
|
assert not is_forward_context_available()
|
|
|
|
|
|
|
|
|
|
with set_forward_context(vllm_config=vllm_config):
|
|
|
|
|
assert is_forward_context_available()
|
|
|
|
|
assert get_forward_context().vllm_config is vllm_config
|
|
|
|
|
|
|
|
|
|
assert not is_forward_context_available()
|
|
|
|
|
assert calls == [
|
|
|
|
|
("set_current_vllm_config", vllm_config),
|
|
|
|
|
("ir_op_priority", None),
|
|
|
|
|
("enable_torch_wrap", vllm_config.compilation_config.ir_enable_torch_wrap),
|
|
|
|
|
("enable_torch_wrap_exit", vllm_config.compilation_config.ir_enable_torch_wrap),
|
|
|
|
|
("ir_op_priority_exit", None),
|
|
|
|
|
("set_current_vllm_config_exit", vllm_config),
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.core_model
|
|
|
|
|
@pytest.mark.cpu
|
|
|
|
|
def test_vllm_set_forward_context_implementation(monkeypatch):
|
|
|
|
|
"""Regression test: ensure that vLLM's set_forward_context implementation has changed."""
|
|
|
|
|
import vllm.forward_context as vllm_forward_context
|
|
|
|
|
import vllm.ir
|
|
|
|
|
from vllm.config import CompilationConfig, DeviceConfig, VllmConfig
|
|
|
|
|
|
|
|
|
|
ERROR_MESSAGE = (
|
|
|
|
|
"If this test fails, it likely means that vLLM's set_forward_context (vllm/forward_context.py) implementation has changed. "
|
|
|
|
|
"In this case, we should update our forward_context (vllm_omni/diffusion/forward_context.py) as well. "
|
|
|
|
|
"We should at least confirm that the `try: with (<what's inside?>): yield` part does not miss any information "
|
|
|
|
|
"(typically by calling the same or similar stuff as vLLM). See #3352 for an example. "
|
|
|
|
|
"Then, update this test to reflect the new implementation, and also update test_set_forward_context_enters_vllm_config_contexts."
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
vllm_config = VllmConfig(
|
|
|
|
|
device_config=DeviceConfig(device="cpu"),
|
|
|
|
|
compilation_config=CompilationConfig(),
|
|
|
|
|
)
|
|
|
|
|
calls = []
|
|
|
|
|
|
|
|
|
|
@contextmanager
|
|
|
|
|
def _set_priority():
|
|
|
|
|
calls.append(("ir_op_priority", None))
|
|
|
|
|
yield
|
|
|
|
|
calls.append(("ir_op_priority_exit", None))
|
|
|
|
|
|
|
|
|
|
@contextmanager
|
|
|
|
|
def _enable_torch_wrap(flag):
|
|
|
|
|
calls.append(("enable_torch_wrap", flag))
|
|
|
|
|
yield
|
|
|
|
|
calls.append(("enable_torch_wrap_exit", flag))
|
|
|
|
|
|
|
|
|
|
def _set_additional_forward_context(**kwargs):
|
|
|
|
|
calls.append(("set_additional_forward_context", tuple(sorted(kwargs.keys()))))
|
|
|
|
|
return {}
|
|
|
|
|
|
|
|
|
|
monkeypatch.setattr(vllm_config.kernel_config.ir_op_priority, "set_priority", _set_priority)
|
|
|
|
|
monkeypatch.setattr(vllm.ir, "enable_torch_wrap", _enable_torch_wrap)
|
|
|
|
|
monkeypatch.setattr(
|
|
|
|
|
vllm_forward_context.current_platform,
|
|
|
|
|
"set_additional_forward_context",
|
|
|
|
|
_set_additional_forward_context,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
assert not vllm_forward_context.is_forward_context_available(), ERROR_MESSAGE
|
|
|
|
|
|
|
|
|
|
with vllm_forward_context.set_forward_context(None, vllm_config):
|
|
|
|
|
assert vllm_forward_context.is_forward_context_available(), ERROR_MESSAGE
|
|
|
|
|
assert vllm_forward_context.get_forward_context().attn_metadata is None, ERROR_MESSAGE
|
|
|
|
|
|
|
|
|
|
assert not vllm_forward_context.is_forward_context_available(), ERROR_MESSAGE
|
|
|
|
|
assert calls == [
|
|
|
|
|
(
|
|
|
|
|
"set_additional_forward_context",
|
|
|
|
|
(
|
|
|
|
|
"attn_metadata",
|
|
|
|
|
"batch_descriptor",
|
|
|
|
|
"cudagraph_runtime_mode",
|
|
|
|
|
"dp_metadata",
|
|
|
|
|
"num_tokens",
|
|
|
|
|
"num_tokens_across_dp",
|
|
|
|
|
"ubatch_slices",
|
|
|
|
|
"vllm_config",
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
], ERROR_MESSAGE
|