rebase: close the remaining vLLM 0.29 drift found by CI 3009
Five further removals/renames, each traced from a failing 3009 job: - StageEngineCoreProcManager mirrors the parent __init__ rather than calling super(), and 0.29 added _request_shutdown_timeout there. The inherited shutdown() read it, raised AttributeError, and left the engine core subprocesses running, so the test process hung at interpreter exit until the 15 minute job timeout. That is the whole of the Engine&Model Executor exit-124: its pytest reported 567 passed, then sat idle for 663s. The failure surfaced only as a StagePool warning, never as a test failure. - PromptUpdateDetails.select_text is gone; prompt updates are token oriented now. MiniCPM-o 4.5 kept three text-based image/video/audio replacements, which crashed stage-0 startup and account for the whole MiniCPM-o cluster. They encode the text and select the unk placeholder by token id instead. - Qwen3-Omni: 0.29 marks audio_feature_lengths keep_on_cpu, while the audio tower derives device placement from feature_lens, so the mask comparison mixed cuda and cpu tensors. Moved explicitly, matching upstream Qwen3OmniMoeThinker._process_audio_input. - AttentionBackend.get_kv_cache_shape is gone; the per-layer shape comes from the spec via compute_layer_kv_cache_shape_bytes, whose content dim is in bytes. - WeightsMapper.get_unstacked_mapper is renamed to get_rename_mapper. tests/engine/test_async_omni_engine_abort.py::test_abort fails here both with and without these changes, so it is environmental rather than a regression. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0146Xu5Sgj4vXxLxvLjV5YPj Signed-off-by: tzhouam <tzhouam@connect.ust.hk>
This commit is contained in:
1 parent
9a399adba8
commit
c1e32fc01d
5 files changed
+42
-19
No files matched your search
@@ -1,5 +1,5 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
|
||||
|
||||
import pytest
|
||||
import torch
|
||||
@@ -214,11 +214,20 @@ def test_fish_kvcache_backend_wraps_only_model_instance(monkeypatch):
|
||||
assert fish_kvcache_backend.get_fish_kvcache_attn_stats()["small_hit_count"] == 1
|
||||
|
||||
|
||||
def _vllm_kv_cache_shape(num_blocks, block_size, num_kv_heads, head_size):
|
||||
def _vllm_kv_cache_shape(num_blocks, block_size, num_kv_heads, head_size, dtype=torch.float16):
|
||||
# Source of truth for the paged KV cache layout the backend must unpack.
|
||||
from vllm.v1.attention.backends.flash_attn import FlashAttentionBackend
|
||||
# vLLM 0.29 removed AttentionBackend.get_kv_cache_shape; the per-layer shape
|
||||
# now comes from the spec, with the content dim expressed in bytes.
|
||||
from vllm.v1.kv_cache_interface import FullAttentionSpec, compute_layer_kv_cache_shape_bytes
|
||||
|
||||
return FlashAttentionBackend.get_kv_cache_shape(num_blocks, block_size, num_kv_heads, head_size)
|
||||
spec = FullAttentionSpec(
|
||||
block_size=block_size,
|
||||
num_kv_heads=num_kv_heads,
|
||||
head_size=head_size,
|
||||
dtype=dtype,
|
||||
)
|
||||
num_pages, num_heads, num_states, content_bytes = compute_layer_kv_cache_shape_bytes(spec, num_blocks)
|
||||
return (num_pages, num_heads, num_states, content_bytes // dtype.itemsize)
|
||||
|
||||
|
||||
def test_fish_kvcache_backend_unbinds_kv_on_vllm_cache_layout(monkeypatch):
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
|
||||
"""Tests for component routing for quantization."""
|
||||
|
||||
from unittest.mock import MagicMock
|
||||
@@ -372,7 +372,8 @@ class TestComponentApplyVllmMapper:
|
||||
"thinker.model": "thinker.language_model.model",
|
||||
"talker.model": "talker.language_model.model",
|
||||
}
|
||||
).get_unstacked_mapper()
|
||||
# vLLM 0.29 renamed get_unstacked_mapper to get_rename_mapper.
|
||||
).get_rename_mapper()
|
||||
|
||||
config.apply_vllm_mapper(mapper)
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
|
||||
|
||||
"""Process manager for omni stage engine subprocesses.
|
||||
|
||||
@@ -83,6 +83,12 @@ class StageEngineCoreProcManager(CoreEngineProcManager):
|
||||
if local_engine_count <= 0:
|
||||
raise ValueError(f"local_engine_count must be > 0, got {local_engine_count}")
|
||||
|
||||
# Mirrors the vLLM 0.29 parent __init__: the inherited shutdown() reads
|
||||
# this to bound how long in-flight requests may drain. Omitting it makes
|
||||
# shutdown raise AttributeError, which leaves the engine core
|
||||
# subprocesses alive and hangs interpreter exit until the job timeout.
|
||||
self._request_shutdown_timeout = vllm_config.shutdown_timeout
|
||||
|
||||
context = get_mp_context()
|
||||
common_kwargs: dict[str, object] = {
|
||||
"vllm_config": vllm_config,
|
||||
|
||||
@@ -3640,6 +3640,17 @@ class MiniCPMO45OmniLLMMultiModalProcessor(BaseMultiModalProcessor[MiniCPMO45Omn
|
||||
additional_placeholders.append((modality, sub_pattern))
|
||||
placeholders += additional_placeholders
|
||||
|
||||
# vLLM 0.29 removed PromptUpdateDetails.select_text: prompt updates are
|
||||
# token oriented now, so encode the replacement text and select the unk
|
||||
# placeholder positions by token id instead of by text.
|
||||
unk_token_id = tokenizer.convert_tokens_to_ids("<unk>")
|
||||
|
||||
def _select_unk_positions(text: str) -> PromptUpdateDetails:
|
||||
return PromptUpdateDetails.select_token_id(
|
||||
tokenizer.encode(text, add_special_tokens=False),
|
||||
unk_token_id,
|
||||
)
|
||||
|
||||
image_max_slice_nums = hf_processor_mm_kwargs.get("max_slice_nums")
|
||||
image_use_image_id = hf_processor_mm_kwargs.get("use_image_id")
|
||||
|
||||
@@ -3648,14 +3659,13 @@ class MiniCPMO45OmniLLMMultiModalProcessor(BaseMultiModalProcessor[MiniCPMO45Omn
|
||||
|
||||
image_size = images.get_image_size(item_idx)
|
||||
|
||||
return PromptUpdateDetails.select_text(
|
||||
return _select_unk_positions(
|
||||
self.get_image_prompt_texts(
|
||||
image_size,
|
||||
item_idx,
|
||||
max_slice_nums=None if image_max_slice_nums is None else int(image_max_slice_nums), # type: ignore[arg-type]
|
||||
use_image_id=None if image_use_image_id is None else bool(image_use_image_id),
|
||||
),
|
||||
"<unk>",
|
||||
)
|
||||
)
|
||||
|
||||
def get_video_replacement(item_idx: int):
|
||||
@@ -3664,10 +3674,7 @@ class MiniCPMO45OmniLLMMultiModalProcessor(BaseMultiModalProcessor[MiniCPMO45Omn
|
||||
frame_size = videos.get_frame_size(item_idx)
|
||||
num_frames = videos.get_num_frames(item_idx)
|
||||
|
||||
return PromptUpdateDetails.select_text(
|
||||
self.get_video_prompt_texts(frame_size, num_frames),
|
||||
"<unk>",
|
||||
)
|
||||
return _select_unk_positions(self.get_video_prompt_texts(frame_size, num_frames))
|
||||
|
||||
get_replacement = {
|
||||
"image": get_image_replacement,
|
||||
@@ -3694,10 +3701,7 @@ class MiniCPMO45OmniLLMMultiModalProcessor(BaseMultiModalProcessor[MiniCPMO45Omn
|
||||
else:
|
||||
audio_len = audios.get_audio_length(item_idx)
|
||||
|
||||
return PromptUpdateDetails.select_text(
|
||||
self.get_audio_prompt_texts(audio_len),
|
||||
"<unk>",
|
||||
)
|
||||
return _select_unk_positions(self.get_audio_prompt_texts(audio_len))
|
||||
|
||||
return [
|
||||
*base_updates,
|
||||
|
||||
@@ -1084,7 +1084,10 @@ class Qwen3OmniMoeConditionalGenerationMixin(Qwen2_5OmniConditionalGenerationMix
|
||||
audio_input: Qwen2_5OmniAudioFeatureInputs,
|
||||
) -> tuple[torch.Tensor, ...]:
|
||||
input_features = audio_input["input_features"]
|
||||
audio_feature_lengths = audio_input["audio_feature_lengths"]
|
||||
# vLLM 0.29 marks audio_feature_lengths keep_on_cpu, and the audio tower
|
||||
# derives device placement from feature_lens, so move it explicitly.
|
||||
# Mirrors upstream Qwen3OmniMoeThinker._process_audio_input.
|
||||
audio_feature_lengths = audio_input["audio_feature_lengths"].to(input_features.device, non_blocking=True)
|
||||
|
||||
audio_output_lengths = _get_feat_extract_output_lengths(audio_feature_lengths)
|
||||
|
||||
|
||||
Reference in new issue
Block a user