Files
vllm-omni/tests/platforms/test_cpu_platform.py
T
tzhouamandClaude Fable 5.1 35e43b9983 [Edge][WP3] Add CPU OmniPlatform (AR + generation stages on vLLM's CPU backend)
* vllm_omni/platforms/cpu/platform.py: CPUOmniPlatform(OmniPlatform, CpuPlatform)
  selected when VLLM_TARGET_DEVICE=cpu or a +cpu vLLM wheel is installed
  (builtin plugin "cpu"; explicit CPU target short-circuits accelerator probes
  like vLLM does). NUMA-based memory queries, one logical device, no graph
  wrapper (sentinel type for isinstance checks), inductor opt-in via
  VLLM_OMNI_CPU_INDUCTOR=1, diffusion stages unsupported.
* vllm_omni/platforms/cpu/worker: CPUARWorker / CPUGenerationWorker compose
  vLLM's CPUWorker with the Omni mixin (XPU pattern); CPUARModelRunner /
  CPUGenerationModelRunner compose the Omni runners with CPUModelRunner
  (no graphs, no async omni output; sleep/wake return error ACKs).
* patch.py skips the CuMem patch on CPU-only torch; Qwen3-TTS speaker encoder
  and prompt-embeds dtype follow the model dtype (float32/float16 on CPU).
* vllm_omni/deploy/qwen3_tts.yaml: `platforms: cpu:` overlay (eager, no async
  scheduling, absolute kv_cache_memory_bytes, disjoint OMP thread ranges).
* requirements/cpu.txt (+psutil, intel-openmp), docs/getting_started/installation/cpu.md.

Measured (this x86 Xeon 8480C host, vllm 0.28.0+cpu, bf16, 12+4 threads):
Qwen3-TTS 0.6B CustomVoice end-to-end on CPU, 12 prompts: TTFA p50 292 ms,
RTF ~1.7 (25-frame chunk ~4.6 s), init 185 s. Result JSON + init timeline
committed under benchmarks/tts/edge_results/.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-09 11:02:14 +08:00

92 lines
4.1 KiB
Python

"""CPU OmniPlatform: registration, MRO, config forcing (CPU, no accelerator needed)."""
from __future__ import annotations
import pytest
import torch
from vllm.platforms.cpu import CpuPlatform
from vllm.platforms.interface import Platform
import vllm_omni.platforms as omni_platforms
from vllm_omni.platforms.cpu.platform import CPUOmniPlatform
from vllm_omni.platforms.interface import OmniPlatform, OmniPlatformEnum
pytestmark = [pytest.mark.core_model, pytest.mark.cpu]
def test_registered_and_selected_when_cpu_target(monkeypatch):
assert "cpu" in omni_platforms.builtin_omni_platform_plugins
monkeypatch.setattr(omni_platforms, "_cpu_target_requested", lambda: True)
assert omni_platforms.cpu_omni_platform_plugin() == omni_platforms._CPU_OMNI_PLATFORM
assert omni_platforms.resolve_current_omni_platform_cls_qualname() == omni_platforms._CPU_OMNI_PLATFORM
monkeypatch.setattr(omni_platforms, "_cpu_target_requested", lambda: False)
assert omni_platforms.cpu_omni_platform_plugin() is None
def test_cpu_target_requested_reads_env(monkeypatch):
import vllm.envs as envs
monkeypatch.setattr(envs, "VLLM_TARGET_DEVICE", "cpu", raising=False)
assert omni_platforms._cpu_target_requested() is True
def test_mro_and_attributes():
mro = CPUOmniPlatform.__mro__
assert mro.index(OmniPlatform) < mro.index(CpuPlatform) < mro.index(Platform)
p = CPUOmniPlatform()
assert p.is_cpu() and not p.is_cuda() and not p.is_npu()
assert p._omni_enum is OmniPlatformEnum.CPU
assert CPUOmniPlatform.device_name == "cpu" and CPUOmniPlatform.device_type == "cpu"
assert CPUOmniPlatform.dist_backend == "gloo"
assert CPUOmniPlatform.get_device_count() == 1
assert CPUOmniPlatform.get_torch_device() == torch.device("cpu")
assert CPUOmniPlatform.get_device_version() is None
assert CPUOmniPlatform.synchronize() is None
assert CPUOmniPlatform.get_free_memory() > 0
avail, total = CPUOmniPlatform.get_device_memory()
assert 0 < avail <= total
assert CPUOmniPlatform.get_device_total_memory() > 0
assert CPUOmniPlatform.supports_talker_mtp_graph_capture() is False
assert CPUOmniPlatform.supports_torch_inductor() is False
assert CPUOmniPlatform.get_default_stage_config_path() == "vllm_omni/deploy"
assert "cpu_ar_worker.CPUARWorker" in CPUOmniPlatform.get_omni_ar_worker_cls()
assert "CPUGenerationWorker" in CPUOmniPlatform.get_omni_generation_worker_cls()
wrapper_cls = CPUOmniPlatform.get_graph_wrapper_cls()
assert isinstance(wrapper_cls, type) and not isinstance(object(), wrapper_cls)
with pytest.raises(NotImplementedError):
wrapper_cls()
with pytest.raises(NotImplementedError):
CPUOmniPlatform.get_diffusion_worker_cls()
def test_inductor_opt_in(monkeypatch):
monkeypatch.setenv("VLLM_OMNI_CPU_INDUCTOR", "1")
assert CPUOmniPlatform.supports_torch_inductor() is True
def test_check_and_update_config_forces_cpu_rules():
from vllm.config import VllmConfig
from vllm.config.device import DeviceConfig
cfg = VllmConfig(device_config=DeviceConfig(device="cpu"))
cfg.scheduler_config.async_scheduling = True
CPUOmniPlatform.check_and_update_config(cfg)
assert cfg.scheduler_config.async_scheduling is False
assert cfg.compilation_config.cudagraph_capture_sizes == []
# worker_cls is resolved by the Omni platform (resolve_worker_cls), not here.
assert cfg.cache_config.block_size == 128
def test_deploy_overlay_for_cpu_platform():
from vllm_omni.config.stage_config import _DEPLOY_DIR, _apply_platform_overrides, load_deploy_config
deploy = load_deploy_config(_DEPLOY_DIR / "qwen3_tts.yaml")
deploy = _apply_platform_overrides(deploy, platform="cpu")
s0, s1 = deploy.stages
assert s0.devices == "cpu" and s1.devices == "cpu"
assert s0.enforce_eager is True and s1.enforce_eager is True
assert s0.async_scheduling is False
assert s0.engine_extras["dtype"] == "bfloat16"
assert s0.engine_extras["kv_cache_memory_bytes"] == 4 * 2**30
assert s0.env["VLLM_CPU_OMP_THREADS_BIND"] != s1.env["VLLM_CPU_OMP_THREADS_BIND"]