[Core] Refactor omni prefix cache into Manager/Controller (#6654)
Signed-off-by: ZhengWG <zwg0606@gmail.com> Co-authored-by: amy-why-3459 <wuhaiyan17@huawei.com> Co-authored-by: Hongsheng Liu <liuhongsheng4@huawei.com>
This commit is contained in:
25 files changed
+5710
-2149
No files matched your search
@@ -18,6 +18,7 @@ from vllm.sampling_params import SamplingParams
|
||||
from vllm.v1.worker import gpu_input_batch
|
||||
from vllm.v1.worker.gpu_input_batch import CachedRequestState, InputBatch
|
||||
|
||||
from vllm_omni.core.prefix_cache import ModelCachePolicy
|
||||
from vllm_omni.entrypoints.openai.protocol.audio import OpenAICreateSpeechRequest
|
||||
from vllm_omni.entrypoints.openai.serving_speech import OmniOpenAIServingSpeech
|
||||
from vllm_omni.entrypoints.openai.tts_adapters.base import PreparedRequest
|
||||
@@ -37,6 +38,8 @@ pytestmark = [pytest.mark.core_model, pytest.mark.cpu]
|
||||
|
||||
def _make_runner(engine_output_type: str | None, downstream_req_ids: set[str]) -> GPUARModelRunner:
|
||||
runner = object.__new__(GPUARModelRunner)
|
||||
runner._omni_cache_policy = ModelCachePolicy(needs_full_hidden_states=True)
|
||||
runner._pooler_payload_include_hidden_flag = True
|
||||
runner.vllm_config = SimpleNamespace(
|
||||
model_config=SimpleNamespace(engine_output_type=engine_output_type),
|
||||
)
|
||||
@@ -57,6 +60,8 @@ def _mtp_runner(*, async_scheduling: bool, buffers: dict[str, dict]) -> tuple[GP
|
||||
return torch.tensor([[11, 12, 13]], dtype=torch.long)
|
||||
|
||||
runner = object.__new__(GPUARModelRunner)
|
||||
runner._omni_cache_policy = ModelCachePolicy(needs_full_hidden_states=True)
|
||||
runner._pooler_payload_include_hidden_flag = True
|
||||
runner.use_async_scheduling = async_scheduling
|
||||
runner.model = SimpleNamespace(post_sample_talker_mtp=post_sample_talker_mtp)
|
||||
runner.requests = {req_id: SimpleNamespace() for req_id in buffers}
|
||||
@@ -143,6 +148,8 @@ def test_post_sample_talker_mtp_uses_gpu_token_with_async_scheduling() -> None:
|
||||
|
||||
def test_post_sample_talker_mtp_skips_shape_validation_without_duplex_rows() -> None:
|
||||
runner = object.__new__(GPUARModelRunner)
|
||||
runner._omni_cache_policy = ModelCachePolicy(needs_full_hidden_states=True)
|
||||
runner._pooler_payload_include_hidden_flag = True
|
||||
runner.use_async_scheduling = False
|
||||
runner.model = SimpleNamespace(
|
||||
post_sample_talker_mtp=lambda **_: pytest.fail("hook must not run"),
|
||||
@@ -178,6 +185,8 @@ def test_post_sample_talker_mtp_rejects_invalid_selected_token_shape(
|
||||
error_match: str,
|
||||
) -> None:
|
||||
runner = object.__new__(GPUARModelRunner)
|
||||
runner._omni_cache_policy = ModelCachePolicy(needs_full_hidden_states=True)
|
||||
runner._pooler_payload_include_hidden_flag = True
|
||||
runner.use_async_scheduling = False
|
||||
runner.model = SimpleNamespace(
|
||||
post_sample_talker_mtp=lambda **_: pytest.fail("hook must not run"),
|
||||
@@ -265,6 +274,8 @@ def test_speech_extra_params_reach_model_sampler_as_sampling_metadata(monkeypatc
|
||||
|
||||
received = []
|
||||
runner = object.__new__(GPUARModelRunner)
|
||||
runner._omni_cache_policy = ModelCachePolicy(needs_full_hidden_states=True)
|
||||
runner._pooler_payload_include_hidden_flag = True
|
||||
runner.input_batch = input_batch
|
||||
runner.model = SimpleNamespace(
|
||||
prefer_model_sampler=True,
|
||||
@@ -323,6 +334,8 @@ def test_sparse_mm_req_ids_requires_sparse_audio_marker():
|
||||
|
||||
def test_runner_assisted_full_attention_metadata_request_is_opt_in():
|
||||
runner = object.__new__(GPUARModelRunner)
|
||||
runner._omni_cache_policy = ModelCachePolicy(needs_full_hidden_states=True)
|
||||
runner._pooler_payload_include_hidden_flag = True
|
||||
runner.model = object()
|
||||
runner.scheduler_config = SimpleNamespace(max_num_seqs=16)
|
||||
|
||||
@@ -377,6 +390,8 @@ def test_runner_assisted_full_attention_metadata_request_and_context_hooks():
|
||||
calls.append(("context", {"enabled": enabled, "num_reqs": num_reqs}))
|
||||
|
||||
runner = object.__new__(GPUARModelRunner)
|
||||
runner._omni_cache_policy = ModelCachePolicy(needs_full_hidden_states=True)
|
||||
runner._pooler_payload_include_hidden_flag = True
|
||||
runner.model = Model()
|
||||
runner.scheduler_config = SimpleNamespace(max_num_seqs=8)
|
||||
|
||||
@@ -466,6 +481,8 @@ def test_omni_async_gpu_model_runner_output_reraises_background_exception():
|
||||
|
||||
def _make_async_output_runner(engine_output_type: str = "audio"):
|
||||
runner = object.__new__(GPUARModelRunner)
|
||||
runner._omni_cache_policy = ModelCachePolicy(needs_full_hidden_states=True)
|
||||
runner._pooler_payload_include_hidden_flag = True
|
||||
model_config = SimpleNamespace(
|
||||
engine_output_type=engine_output_type,
|
||||
async_chunk=True,
|
||||
@@ -642,10 +659,11 @@ def test_async_omni_output_guard_requires_safe_conditions():
|
||||
|
||||
assert GPUARModelRunner._should_use_async_omni_output(runner)
|
||||
|
||||
# Prefix cache no longer forces the sync output path; leftover mm is
|
||||
# snapshotted at save so the builder can materialize a step late.
|
||||
runner.omni_prefix_cache = object()
|
||||
assert not GPUARModelRunner._should_use_async_omni_output(runner)
|
||||
assert GPUARModelRunner._should_use_async_omni_output(runner)
|
||||
|
||||
runner.omni_prefix_cache = None
|
||||
runner.model.has_postprocess = True
|
||||
assert not GPUARModelRunner._should_use_async_omni_output(runner)
|
||||
|
||||
@@ -656,6 +674,7 @@ def test_async_omni_output_guard_requires_safe_conditions():
|
||||
def test_build_omni_output_skips_hidden_when_model_opts_out(monkeypatch):
|
||||
runner = _make_async_output_runner(engine_output_type="latent")
|
||||
runner.model.omni_pooler_payload_include_hidden = False
|
||||
runner._pooler_payload_include_hidden_flag = False
|
||||
|
||||
monkeypatch.setattr(
|
||||
GPUARModelRunner,
|
||||
@@ -699,6 +718,7 @@ def test_build_omni_output_skips_hidden_when_model_opts_out(monkeypatch):
|
||||
def test_build_omni_output_splits_mm_by_scheduled_tokens_when_hidden_is_tail_only(monkeypatch):
|
||||
runner = _make_async_output_runner(engine_output_type="latent")
|
||||
runner.model.omni_pooler_payload_include_hidden = False
|
||||
runner._pooler_payload_include_hidden_flag = False
|
||||
runner._async_chunk = False
|
||||
runner.requests = {"r1": object(), "r2": object(), "r3": object()}
|
||||
|
||||
@@ -745,6 +765,7 @@ def test_build_omni_output_splits_mm_by_hidden_len_when_scheduled_is_padded(monk
|
||||
"""Thinker mm rows align to hidden_states.shape[0], not padded scheduled count."""
|
||||
runner = _make_async_output_runner(engine_output_type="latent")
|
||||
runner.model.omni_pooler_payload_include_hidden = False
|
||||
runner._pooler_payload_include_hidden_flag = False
|
||||
runner._async_chunk = False
|
||||
runner.requests = {"r1": object(), "r2": object(), "r3": object()}
|
||||
|
||||
@@ -790,6 +811,7 @@ def test_build_omni_output_splits_mm_by_hidden_len_when_scheduled_is_padded(monk
|
||||
def test_async_snapshot_payload_omits_hidden_when_model_opts_out():
|
||||
runner = _make_async_output_runner()
|
||||
runner.model.omni_pooler_payload_include_hidden = False
|
||||
runner._pooler_payload_include_hidden_flag = False
|
||||
|
||||
payload = GPUARModelRunner._build_omni_async_snapshot_payload(
|
||||
runner,
|
||||
@@ -819,6 +841,8 @@ def test_runner_assisted_full_attention_metadata_refresh_pads_buffers():
|
||||
self.commits.append(num_reqs_padded)
|
||||
|
||||
runner = object.__new__(GPUARModelRunner)
|
||||
runner._omni_cache_policy = ModelCachePolicy(needs_full_hidden_states=True)
|
||||
runner._pooler_payload_include_hidden_flag = True
|
||||
block_table = BlockTable()
|
||||
runner.input_batch = SimpleNamespace(
|
||||
num_computed_tokens_cpu=torch.tensor([10, 20, 99, 99], dtype=torch.int32),
|
||||
@@ -846,6 +870,8 @@ def test_runner_assisted_full_attention_metadata_refresh_pads_buffers():
|
||||
@pytest.mark.parametrize("query_start_loc_attr", ["method", "tensor_attr"])
|
||||
def test_sample_tokens_tail_only_prefix_cache_uses_staged_cpu_hidden_states(monkeypatch, query_start_loc_attr):
|
||||
runner = object.__new__(GPUARModelRunner)
|
||||
runner._omni_cache_policy = ModelCachePolicy(needs_full_hidden_states=True)
|
||||
runner._pooler_payload_include_hidden_flag = True
|
||||
runner.execute_model_state = ExecuteModelState(
|
||||
SimpleNamespace(
|
||||
total_num_scheduled_tokens=3,
|
||||
@@ -908,12 +934,11 @@ def test_sample_tokens_tail_only_prefix_cache_uses_staged_cpu_hidden_states(monk
|
||||
)
|
||||
monkeypatch.setattr(GPUARModelRunner, "eplb_step", lambda self: None)
|
||||
monkeypatch.setattr(GPUARModelRunner, "_resolve_pooler_payload_req_ids", lambda self, req_ids: ("audio", req_ids))
|
||||
monkeypatch.setattr(GPUARModelRunner, "_deferred_prefix_cache_mm_keys", lambda self: set())
|
||||
monkeypatch.setattr(GPUARModelRunner, "_model_needs_full_prefix_hidden_states", lambda self: False)
|
||||
monkeypatch.setattr(
|
||||
GPUARModelRunner,
|
||||
"_maybe_get_combined_prefix_cache_tensors",
|
||||
lambda *args, **kwargs: (None, None),
|
||||
"_prepare_prefix_cache_pooler_payload_sources",
|
||||
lambda self, **kwargs: (kwargs["staged_hidden_states_cpu"], None, None),
|
||||
)
|
||||
monkeypatch.setattr(GPUARModelRunner, "_process_additional_information_updates", lambda *args, **kwargs: None)
|
||||
monkeypatch.setattr(GPUARModelRunner, "_should_accumulate_full_payload_output", lambda self: False)
|
||||
@@ -946,8 +971,6 @@ def test_build_omni_output_falls_back_to_mm_cpu_without_prefix_merge(monkeypatch
|
||||
lambda self, req_ids: ("latent", req_ids),
|
||||
)
|
||||
monkeypatch.setattr(GPUARModelRunner, "_model_needs_full_prefix_hidden_states", lambda self: False)
|
||||
monkeypatch.setattr(GPUARModelRunner, "_deferred_prefix_cache_mm_keys", lambda self: {"codes.audio"})
|
||||
monkeypatch.setattr(GPUARModelRunner, "_stage_deferred_prefix_cache_mm_outputs", lambda *args, **kwargs: None)
|
||||
monkeypatch.setattr(
|
||||
GPUARModelRunner,
|
||||
"_prepare_prefix_cache_pooler_payload_sources",
|
||||
@@ -1095,8 +1118,6 @@ def test_build_omni_output_filters_multimodal_by_partial_downstream_batch(monkey
|
||||
lambda self, req_ids: ("latent", ["r1", "r3"]),
|
||||
)
|
||||
monkeypatch.setattr(GPUARModelRunner, "_model_needs_full_prefix_hidden_states", lambda self: False)
|
||||
monkeypatch.setattr(GPUARModelRunner, "_deferred_prefix_cache_mm_keys", lambda self: {"codes.audio"})
|
||||
monkeypatch.setattr(GPUARModelRunner, "_stage_deferred_prefix_cache_mm_outputs", lambda *args, **kwargs: None)
|
||||
monkeypatch.setattr(
|
||||
GPUARModelRunner,
|
||||
"_prepare_prefix_cache_pooler_payload_sources",
|
||||
@@ -1172,8 +1193,6 @@ def test_build_omni_output_uses_combined_prefix_cache_mm_payload_for_partial_dow
|
||||
lambda self, req_ids: ("latent", ["r1", "r3"]),
|
||||
)
|
||||
monkeypatch.setattr(GPUARModelRunner, "_model_needs_full_prefix_hidden_states", lambda self: False)
|
||||
monkeypatch.setattr(GPUARModelRunner, "_deferred_prefix_cache_mm_keys", lambda self: {"codes.audio"})
|
||||
monkeypatch.setattr(GPUARModelRunner, "_stage_deferred_prefix_cache_mm_outputs", lambda *args, **kwargs: None)
|
||||
monkeypatch.setattr(
|
||||
GPUARModelRunner,
|
||||
"_prepare_prefix_cache_pooler_payload_sources",
|
||||
|
||||
Reference in new issue
Block a user