Files
vllm-omni/tests/edge/test_calibrate.py
T
tzhouamandClaude Fable 5.1 55192de984 [Edge][WP4] Add hardware adaptation: probe, derived overrides, auto profile, calibration
* 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>
2026-09-09 11:01:40 +08:00

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