[Model] Make the dummy-run recipe feature-neutral

Per review, the warmup recipe is a property of the model's request
geometry, not of distributed layerwise offload: rename
dlo_dummy_run_recipe to dummy_run_recipe and drop the DLO gate in
_make_dummy_request. A model whose geometry needs recipe-specific sampling
arguments warms up at startup whatever features are enabled — under DLO
the generation also primes the component cache-retention budget; without
it, the same warmup covers any other first-request cost. Validated both
ways on L20X: DLO boot unchanged (releases stay in the startup window) and
a non-DLO MiniMax-H3 boot now runs the warmup and serves normally.

Signed-off-by: hsliuustc0106 <liuhongsheng4@huawei.com>
This commit is contained in:
hsliuustc0106 committed 2026-08-26 15:48:07 +08:00
1 parent 33297bdb9d
commit e1c4b6153a
6 files changed
+53 -49

No files matched your search

@@ -185,9 +185,10 @@ resolution. It starts at zero: a cold start pays one release per observation
step while the peak climbs, after which boundaries retain steadily, and a
workload change whose cached footprint grows by more than the margin pays one
further release while the new peak lands. Models whose request geometry opts
out of the generic dummy run can declare `dlo_dummy_run_recipe`; MiniMax-H3
declares one minimal t2va generation, so under DLO the engine's startup
warmup runs it and the cold-start flushes land before real traffic. The budget is capped at a quarter
out of the generic dummy run declare a feature-neutral `dummy_run_recipe`
instead; MiniMax-H3 declares a maximum-duration t2va generation, so the
engine's startup warmup runs it and, under DLO, the cold-start flushes land
before real traffic. The budget is capped at a quarter
of device capacity so a spurious observation cannot monopolize a small
device, and detaching the last attached stager resets the learned peak so one
workload never permanently influences another. No user-chosen fraction, no
@@ -69,13 +69,13 @@ omni = Omni(
## Startup warmup
Under DLO, models that need model-specific sampling arguments for a warmup
generation (currently MiniMax-H3: `t2va`, an explicit aspect ratio) run one
at engine startup. It runs at the maximum output duration so the component
allocator-cache retention policy learns a footprint that covers every
production request: the cold-start flushes happen during startup and no real
request pays them. The tradeoff is one maximum-length generation added to
boot time; on deployments without DLO the behavior is unchanged.
Models whose request geometry needs model-specific sampling arguments for a
warmup generation (currently MiniMax-H3: `t2va`, an explicit aspect ratio)
run one at engine startup whatever features are enabled. It runs at the
maximum output duration so it covers every production request; under DLO
this means the component allocator-cache retention policy learns its
footprint during startup and no real request pays the cold-start flushes.
The tradeoff is one maximum-length generation added to boot time.
## Host-weight loading
@@ -70,7 +70,7 @@ def test_dummy_run_image_count_resolves_hunyuan_architecture_alias() -> None:
assert io_support.get_dummy_run_num_image_inputs("unknown") == 1
def test_dlo_dummy_run_recipe_returns_none_without_declaration(monkeypatch: pytest.MonkeyPatch) -> None:
def test_dummy_run_recipe_returns_none_without_declaration(monkeypatch: pytest.MonkeyPatch) -> None:
class PlainModel:
pass
@@ -80,14 +80,14 @@ def test_dlo_dummy_run_recipe_returns_none_without_declaration(monkeypatch: pyte
lambda model_class_name: PlainModel,
)
assert io_support.get_dlo_dummy_run_recipe("plain") is None
assert io_support.get_dummy_run_recipe("plain") is None
def test_dlo_dummy_run_recipe_returns_copy_of_declaration(monkeypatch: pytest.MonkeyPatch) -> None:
def test_dummy_run_recipe_returns_copy_of_declaration(monkeypatch: pytest.MonkeyPatch) -> None:
declared = {"task": "t2va", "duration": 4.0}
class RecipeModel:
dlo_dummy_run_recipe = declared
dummy_run_recipe = declared
monkeypatch.setattr(
io_support.DiffusionModelRegistry,
@@ -95,7 +95,7 @@ def test_dlo_dummy_run_recipe_returns_copy_of_declaration(monkeypatch: pytest.Mo
lambda model_class_name: RecipeModel,
)
recipe = io_support.get_dlo_dummy_run_recipe("recipe")
recipe = io_support.get_dummy_run_recipe("recipe")
assert recipe == declared
assert recipe is not declared
@@ -106,7 +106,7 @@ def test_minimax_h3_declares_a_valid_dlo_warmup_recipe() -> None:
MiniMaxH3Pipeline,
)
recipe = MiniMaxH3Pipeline.dlo_dummy_run_recipe
recipe = MiniMaxH3Pipeline.dummy_run_recipe
assert recipe is not None
assert recipe["task"] == "t2va"
assert recipe["aspect_ratio"] == "16:9"
@@ -142,17 +142,20 @@ def _opt_out_generic_warmup(
lambda model_class_name, supports_audio_input: 0,
)
monkeypatch.setattr(
"vllm_omni.diffusion.diffusion_engine.get_dlo_dummy_run_recipe",
"vllm_omni.diffusion.diffusion_engine.get_dummy_run_recipe",
lambda model_class_name: recipe,
)
def test_make_dummy_request_skips_recipe_without_dlo(monkeypatch: pytest.MonkeyPatch) -> None:
_opt_out_generic_warmup(monkeypatch, {"task": "t2va"})
def test_make_dummy_request_applies_recipe_without_dlo(monkeypatch: pytest.MonkeyPatch) -> None:
# The recipe is feature-neutral: a model whose geometry needs it warms up
# whatever features are enabled, not only under DLO.
_opt_out_generic_warmup(monkeypatch, {"task": "t2va", "duration": 4.0, "aspect_ratio": "16:9"})
request = _dlo_recipe_engine(enable_dlo=False)._make_dummy_request(height=512, width=512, guidance_scale=0.0)
assert request is None
assert request is not None
assert request.sampling_params.extra_args["task"] == "t2va"
def test_make_dummy_request_builds_recipe_request_when_generic_opted_out(
+13 -14
View File
@@ -34,9 +34,9 @@ from vllm_omni.diffusion.diffusion_kv.config import DiffusionKVCacheMode, is_sch
from vllm_omni.diffusion.diffusion_kv.initialization import initialize_diffusion_kv_control_plane
from vllm_omni.diffusion.executor.abstract import DiffusionExecutor
from vllm_omni.diffusion.io_support import (
get_dlo_dummy_run_recipe,
get_dummy_run_num_frames,
get_dummy_run_num_image_inputs,
get_dummy_run_recipe,
image_color_format,
supports_audio_output,
supports_multimodal_input,
@@ -65,9 +65,9 @@ logger = init_logger(__name__)
_ASYNC_OUTPUT_TIMEOUT_ENV = "VLLM_OMNI_ASYNC_OUTPUT_TIMEOUT"
_ASYNC_OUTPUT_TIMEOUT_DEFAULT = 600.0 # seconds
# DLO warmup-recipe keys applied to the dummy request's sampling params;
# every other recipe entry is forwarded through the request's extra_args.
_DLO_DUMMY_RUN_SAMPLING_KEYS = frozenset({"height", "width", "num_inference_steps", "num_frames", "guidance_scale"})
# Warmup-recipe keys applied to the dummy request's sampling params; every
# other recipe entry is forwarded through the request's extra_args.
_DUMMY_RUN_RECIPE_SAMPLING_KEYS = frozenset({"height", "width", "num_inference_steps", "num_frames", "guidance_scale"})
def _async_output_timeout() -> float:
@@ -1024,19 +1024,18 @@ class DiffusionEngine:
supports_image_input, supports_audio_input = supports_multimodal_input(self.od_config)
num_frames = get_dummy_run_num_frames(self.od_config.model_class_name, supports_audio_input)
if num_frames <= 0:
# The model opted out of the generic dummy run. Under distributed
# layerwise offload, fall back to its declared warmup recipe so one
# startup generation primes the component allocator-cache
# retention policy ahead of real traffic. The recipe names its own
# task, so the request stays text-only even when the model's other
# tasks accept image or audio conditions.
if not getattr(self.od_config, "enable_distributed_layerwise_offload", False):
return None
recipe = get_dlo_dummy_run_recipe(self.od_config.model_class_name)
# The model opted out of the generic dummy run; fall back to its
# declared warmup recipe, which supplies whatever feature-specific
# sampling arguments the model requires (under distributed
# layerwise offload the generation also primes the component
# allocator-cache retention policy ahead of real traffic). The
# recipe names its own task, so the request stays text-only even
# when the model's other tasks accept image or audio conditions.
recipe = get_dummy_run_recipe(self.od_config.model_class_name)
if recipe is None:
return None
extra_args: dict[str, Any] = {"cfg_text_scale": 1.0, "cfg_img_scale": 1.0}
extra_args.update({k: v for k, v in recipe.items() if k not in _DLO_DUMMY_RUN_SAMPLING_KEYS})
extra_args.update({k: v for k, v in recipe.items() if k not in _DUMMY_RUN_RECIPE_SAMPLING_KEYS})
return OmniDiffusionRequest(
prompt={"prompt": "dummy run"},
request_id=DUMMY_DIFFUSION_REQUEST_ID,
+8 -7
View File
@@ -55,18 +55,19 @@ def get_dummy_run_num_frames(model_class_name: str, supports_audio_input: bool)
return 2 if supports_audio_input or supports_audio_output(model_class_name) else 1
def get_dlo_dummy_run_recipe(model_class_name: str) -> dict[str, Any] | None:
"""Get the model-declared DLO startup-warmup recipe, or None.
def get_dummy_run_recipe(model_class_name: str) -> dict[str, Any] | None:
"""Get the model-declared startup-warmup recipe, or None.
Models that opt out of the generic dummy run (``dummy_run_num_frames = 0``)
because their request geometry needs model-specific sampling arguments can
still declare a recipe used only when distributed layerwise offload is
enabled, where one startup generation primes the component allocator-cache
retention policy.
because their request geometry needs model-specific sampling arguments
(task, duration, aspect ratio, ...) declare a recipe instead. The recipe
is feature-neutral: the engine runs it at startup whatever features are
enabled — under distributed layerwise offload the generation also primes
the component allocator-cache retention policy's observed-peak budget.
"""
model_cls = DiffusionModelRegistry._try_load_model_cls(model_class_name)
recipe = getattr(model_cls, "dlo_dummy_run_recipe", None) if model_cls is not None else None
recipe = getattr(model_cls, "dummy_run_recipe", None) if model_cls is not None else None
return dict(recipe) if recipe else None
@@ -704,14 +704,14 @@ class MiniMaxH3Pipeline(
"post_decode",
]
dummy_run_num_frames: ClassVar[int] = 0
# Startup warmup used only when distributed layerwise offload is enabled:
# the generic dummy run cannot satisfy t2va's required sampling arguments
# (explicit aspect ratio, bounded duration). Duration is the only workload
# variable at the fixed 768 short edge, so warming at the maximum makes the
# learned cache-retention peak dominate every production request and moves
# all cold-start flushes ahead of real traffic, at the cost of one
# max-length generation in boot time.
dlo_dummy_run_recipe: ClassVar[Mapping[str, Any] | None] = {
# Startup warmup recipe: the generic dummy run cannot satisfy t2va's
# required sampling arguments (explicit aspect ratio, bounded duration).
# Duration is the only workload variable at the fixed 768 short edge, so
# warming at the maximum covers every production request — under DLO this
# makes the learned cache-retention peak dominate, moving all cold-start
# flushes ahead of real traffic. The cost is one max-length generation in
# boot time whatever features are enabled.
dummy_run_recipe: ClassVar[Mapping[str, Any] | None] = {
"task": "t2va",
"duration": MINIMAX_H3_MAX_OUTPUT_SECONDS,
"aspect_ratio": "16:9",