* vllm_omni/edge/hardware_probe.py: HardwareProfile from /proc, /sys and torch (ISA flags incl. AVX-512/AMX and NEON/dotprod/i8mm/SVE, physical cores, big.LITTLE clusters, NUMA, RAM, CUDA discrete vs Tegra unified memory, NPU via override), hardware classes jetson / cuda_discrete / arm64_cpu / x86_cpu / npu_phone; VLLM_OMNI_HW_PROFILE=<json> overrides the probe (emulation, tests). * vllm_omni/edge/adapt.py: derive_overrides -> dtype, absolute KV budgets from available memory minus weights, max_num_seqs, per-stage disjoint CPU thread ranges on the big cluster, eager/graph switches for small or unified memory, adaptive-chunk parameters, timeouts from a load cost model. * vllm_omni/edge/calibrate.py: chunk-schedule calibration from measured chunk arrivals with a per-hardware-fingerprint cache under VLLM_CACHE_ROOT. * vllm_omni/edge/auto_profile.py + deploy_profile="auto": edge/<model>.yaml -> edge/hardware/<class>.yaml -> derived overrides -> cached calibration, materialized as a temp deploy YAML (platform overlays are superseded). * benchmarks/tts/hw_emulation.py: emulated classes (ATEN_CPU_CAPABILITY, taskset, profile overrides) driving stream_latency_bench with auto profiles. * CPU-only tests for probe snapshots, derivation rules, calibration and auto. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
76 lines
3.0 KiB
Python
76 lines
3.0 KiB
Python
"""Tests for vllm_omni.edge.calibrate (CPU)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
from vllm_omni.edge import calibrate as cal
|
|
from vllm_omni.edge.hardware_probe import HardwareProfile
|
|
|
|
pytestmark = [pytest.mark.core_model, pytest.mark.cpu]
|
|
|
|
SR = 24000
|
|
FRAME = 1920
|
|
|
|
|
|
def _chunks(rate_frames_per_s: float, sizes: list[int], ttfa_ms: float = 30.0):
|
|
"""Synthesize arrivals for a generator producing ``rate`` frames/s."""
|
|
chunks = []
|
|
t = ttfa_ms
|
|
for i, n in enumerate(sizes):
|
|
if i > 0:
|
|
t += n * 1000.0 / rate_frames_per_s
|
|
chunks.append({"t_ms": t, "samples": n * FRAME})
|
|
return chunks
|
|
|
|
|
|
def test_rate_estimate_from_measured_shape():
|
|
# measured on L20X: 25 frames every ~160 ms -> ~156 frames/s
|
|
chunks = [
|
|
{"t_ms": 30.0, "samples": FRAME},
|
|
{"t_ms": 190.0, "samples": 25 * FRAME},
|
|
{"t_ms": 350.0, "samples": 25 * FRAME},
|
|
]
|
|
rate = cal.frames_per_second_from_chunks(chunks, SR)
|
|
assert rate == pytest.approx(50 / 0.32, rel=1e-3)
|
|
assert cal.frames_per_second_from_chunks(chunks[:1], SR) is None
|
|
|
|
|
|
def test_fast_generator_keeps_small_first_chunk_and_no_adaptive():
|
|
sched = cal.derive_chunk_schedule(_chunks(150.0, [1, 25, 25, 25]), SR)
|
|
assert sched["measured"] is True
|
|
assert sched["rtf"] < 0.2
|
|
assert sched["codec_chunk_adaptive"] is False
|
|
assert sched["codec_chunk_min_frames"] == 1
|
|
assert sched["codec_chunk_ramp"][-1] == 25 and sched["codec_chunk_ramp"][0] == 1
|
|
|
|
|
|
def test_slow_generator_needs_lead_and_adaptive():
|
|
# 10 frames/s < 12.5 real time: each 25-frame chunk takes 2.5 s to make but plays 2.0 s
|
|
sched = cal.derive_chunk_schedule(_chunks(10.0, [2, 4, 8, 16, 25, 25]), SR)
|
|
assert sched["rtf"] > 1.0
|
|
assert sched["codec_chunk_adaptive"] is True
|
|
assert sched["codec_chunk_min_frames"] >= 7 # (40 + 20*25) / 80 -> 6.75 -> 7
|
|
assert sched["codec_chunk_ramp"][-1] == 25
|
|
assert all(a < b for a, b in zip(sched["codec_chunk_ramp"], sched["codec_chunk_ramp"][1:]))
|
|
extra = cal.connector_extra_from_calibration(sched)
|
|
assert extra["codec_chunk_adaptive"] is True and extra["codec_chunk_ramp"][-1] == 25
|
|
|
|
|
|
def test_unmeasurable_falls_back_to_defaults():
|
|
sched = cal.derive_chunk_schedule([{"t_ms": 30.0, "samples": FRAME}], SR)
|
|
assert sched["measured"] is False and sched["codec_chunk_ramp"] == [2, 4, 8, 16, 25]
|
|
|
|
|
|
def test_cache_roundtrip(tmp_path, monkeypatch):
|
|
monkeypatch.setenv("VLLM_CACHE_ROOT", str(tmp_path))
|
|
prof = HardwareProfile(arch="x86_64", cpu_model="x", n_physical=8, gpu_name="", gpu_mem_bytes=0)
|
|
fp = cal.hardware_fingerprint(prof, "Qwen/Qwen3-TTS-12Hz-0.6B-CustomVoice")
|
|
assert len(fp) == 16
|
|
assert cal.load_calibration(fp) is None
|
|
p = cal.save_calibration(fp, {"codec_chunk_ramp": [1, 25]})
|
|
assert p.parent == tmp_path / "omni_edge"
|
|
assert cal.load_calibration(fp) == {"codec_chunk_ramp": [1, 25]}
|
|
# different model -> different fingerprint
|
|
assert cal.hardware_fingerprint(prof, "other") != fp
|