[edge-infer] WIP snapshot: uncommitted M0/W1/W4/W5 edge work as of 2026-09-18

Verbatim copy of the edge/omni-edge working tree (tracked diffs + untracked
edge/local, tests/edge/local, docs/edge, pipeline files). Taken so that
vLLM-Omni v0.29.0rc1 can be merged on a branch without touching the
user's working tree. logs_edge/ and benchmark .npy outputs excluded.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
tzhouamandClaude Fable 5.1 committed 2026-09-18 09:47:29 +08:00
1 parent 3834de3105
commit 4e3e8a1ebc
62 files changed
+11043 -56

No files matched your search

@@ -0,0 +1,50 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
"""Pipelines for text models vLLM implements and Omni does not own.
A model being in vLLM's registry does not make it reachable through
``Omni(model=...)``: the orchestrator resolves a pipeline by ``model_type``
before any weight is read, so a ``model_type`` with no entry fails early and
opaquely. Spark-X2.5 hit exactly that; these tests pin the general case.
"""
from __future__ import annotations
import pytest
from vllm_omni.config.pipeline_registry import OMNI_PIPELINES
from vllm_omni.config.stage_config import StageExecutionType
from vllm_omni.config.vllm_native_pipelines import LLAMA_PIPELINE
def test_llama_resolves_from_the_registry():
"""MiniCPM5-2B declares model_type "llama"; without this entry the
orchestrator cannot resolve it at all."""
assert OMNI_PIPELINES["llama"] is LLAMA_PIPELINE
def test_it_is_one_autoregressive_text_stage():
assert LLAMA_PIPELINE.get_validation_errors() == []
assert len(LLAMA_PIPELINE.stages) == 1
stage = LLAMA_PIPELINE.stages[0]
assert stage.execution_type is StageExecutionType.LLM_AR
assert stage.input_sources == ()
assert stage.final_output and stage.final_output_type == "text"
assert stage.owns_tokenizer
assert stage.model_arch == "LlamaForCausalLM"
def test_the_stage_declares_no_cross_chunk_state():
"""A causal LM's state is its KV cache, which the backend owns. Claiming
otherwise would make the scheduler park requests to hold capacity."""
assert not LLAMA_PIPELINE.stages[0].retains_state_across_chunks
def test_registering_llama_is_keyed_on_architecture_not_checkpoint():
"""Worth pinning because it is the surprising part: this entry covers every
checkpoint whose config says "llama", not only the one it was added for.
That is the right granularity — pipeline shape is a property of the
architecture — but it is a claim about shape, not a verification of any
particular weights."""
assert LLAMA_PIPELINE.model_type == "llama"
assert LLAMA_PIPELINE.hf_architectures == ("LlamaForCausalLM",)
View File
Whitespace-only changes.
+154
View File
@@ -0,0 +1,154 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
"""Fixtures for the M0 local text mode.
Everything here is synthetic on purpose: a hardware profile built from
literals, and a checkpoint directory with a real ``config.json`` and
zero-filled weight files. The planner reads sizes and geometry, never tensors,
so this exercises the real code path without a GPU or 7.7 GB of weights. The
one test module that does need real weights says so and skips.
"""
from __future__ import annotations
import json
from pathlib import Path
import pytest
from vllm_omni.edge.hardware_probe import (
ACCEL_GPU_DISCRETE,
ACCEL_GPU_INTEGRATED,
ACCEL_NPU,
HardwareProfile,
)
# A 28-layer Spark-shaped decoder: 7 full-attention and 21 sliding@512, which
# is the 1.7B layout. Small hidden/vocab so nothing here is slow.
SPARK_SHAPED_CONFIG = {
"architectures": ["Spark2_5ForCausalLM"],
"model_type": "spark2_5",
"dtype": "bfloat16",
"hidden_size": 2048,
"intermediate_size": 8192,
"num_hidden_layers": 28,
"num_attention_heads": 8,
"num_key_value_heads": 2,
"head_dim": 256,
"hidden_act": "gelu",
"vocab_size": 131072,
"sliding_window": 512,
"max_position_embeddings": 1048576,
"tie_word_embeddings": True,
"layer_types": [
"full_attention" if (i + 1) % 4 == 0 else "sliding_attention"
for i in range(28)
],
"rope_parameters": {
"full_attention": {"rope_theta": 5000000, "partial_rotary_factor": 0.25},
"sliding_attention": {"rope_theta": 10000, "partial_rotary_factor": 1.0},
},
}
INT8_QUANT_CONFIG = {
"quant_method": "compressed-tensors",
"format": "int-quantized",
"quantization_status": "compressed",
"ignore": ["lm_head"],
"config_groups": {
"group_0": {
"targets": ["Linear"],
"weights": {"num_bits": 8, "type": "int", "symmetric": True, "strategy": "channel"},
}
},
}
FP8_QUANT_CONFIG = {
"quant_method": "compressed-tensors",
"format": "float-quantized",
"config_groups": {},
}
def write_checkpoint(
root: Path,
*,
quantization: dict | None = None,
weight_bytes: int = 4 * 1024 * 1024,
shards: int = 1,
) -> Path:
"""A checkpoint directory the manifest and planner can read end to end."""
root.mkdir(parents=True, exist_ok=True)
config = dict(SPARK_SHAPED_CONFIG)
if quantization is not None:
config["quantization_config"] = quantization
(root / "config.json").write_text(json.dumps(config), encoding="utf-8")
(root / "tokenizer_config.json").write_text('{"model_max_length": 4096}', encoding="utf-8")
(root / "chat_template.jinja").write_text("{{ messages }}", encoding="utf-8")
per_shard = max(weight_bytes // shards, 1)
for i in range(shards):
name = "model.safetensors" if shards == 1 else f"model-{i + 1:05d}-of-{shards:05d}.safetensors"
with (root / name).open("wb") as fh:
fh.truncate(per_shard)
return root
@pytest.fixture
def dense_checkpoint(tmp_path: Path) -> Path:
return write_checkpoint(tmp_path / "dense", weight_bytes=8 * 1024 * 1024, shards=2)
@pytest.fixture
def int8_checkpoint(tmp_path: Path) -> Path:
return write_checkpoint(tmp_path / "int8", quantization=INT8_QUANT_CONFIG)
def blackwell_laptop(ram_available_bytes: int = 28 * 2**30) -> HardwareProfile:
"""The reference machine: sm_120 discrete GPU, an iGPU and an NPU beside it.
Modelled on the probe output recorded in the architecture proposal, so the
tests exercise the same shape the real host produces.
"""
return HardwareProfile(
arch="x86_64",
cpu_model="AMD Ryzen AI 9 HX 370 w/ Radeon 890M",
cpu_flags=["avx2", "avx512", "avx512_bf16", "avx512_vnni", "fma"],
n_logical=24,
n_physical=12,
clusters=[{"max_khz": 5000000, "cpus": list(range(24))}],
ram_total_bytes=int(30.91 * 2**30),
ram_available_bytes=ram_available_bytes,
accelerator="cuda_discrete",
gpu_name="NVIDIA GeForce RTX 5090 Laptop GPU",
gpu_mem_bytes=24463 * 2**20,
gpu_sm_count=110,
gpu_capability=[12, 0],
supports_bf16=True,
host_os="wsl2",
accelerators=[
{"kind": ACCEL_GPU_DISCRETE, "vendor": "nvidia",
"name": "NVIDIA GeForce RTX 5090 Laptop GPU", "usable": True,
"source": "torch.cuda", "mem_bytes": 24463 * 2**20},
{"kind": ACCEL_NPU, "vendor": "amd", "name": "NPU Compute Accelerator Device",
"usable": False, "source": "wsl-host", "reason": "no device node under WSL2"},
{"kind": ACCEL_GPU_INTEGRATED, "vendor": "amd", "name": "AMD Radeon(TM) 890M Graphics",
"usable": False, "source": "wsl-host", "reason": "no /dev/dri under WSL2"},
],
source="test-fixture",
)
def cpu_only_box() -> HardwareProfile:
"""The no-NVIDIA deployment class, as a machine rather than as a mask."""
profile = blackwell_laptop()
profile.accelerator = "none"
profile.gpu_name = ""
profile.gpu_mem_bytes = 0
profile.gpu_capability = []
profile.accelerators = [a for a in profile.accelerators if a["vendor"] != "nvidia"]
return profile
@pytest.fixture
def laptop_profile() -> HardwareProfile:
return blackwell_laptop()
View File
Whitespace-only changes.
+96
View File
@@ -0,0 +1,96 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
"""Fixtures that stand in for the two AMD devices.
Nothing here needs a Radeon, an NPU, onnxruntime or Windows: the worker is
replaced by ``fake_worker.py`` and the devices by hand-built capabilities. The
paths that matter -- framing, the placement gate, the refusal codes -- are
logic, and logic that only runs on one laptop is logic nobody can change
safely.
"""
from __future__ import annotations
import json
import sys
from pathlib import Path
import pytest
from vllm_omni.edge.local.capabilities import (
FORMAT_ONNX_A16W8,
FORMAT_ONNX_FP16,
FORMAT_ONNX_FP32,
DeviceCapability,
)
from vllm_omni.edge.local.external import launch
FAKE_WORKER = str(Path(__file__).resolve().parent / "fake_worker.py")
@pytest.fixture
def fake_route(monkeypatch, tmp_path):
"""Point the ``ort-cpu`` route at the fake worker and this interpreter.
Returns a callable that writes the worker's reply script and hands back the
resolved route.
"""
def configure(**config) -> launch.Route:
config_path = tmp_path / "fake_worker.json"
config_path.write_text(json.dumps(config))
monkeypatch.setenv("VLLM_OMNI_FAKE_WORKER_JSON", str(config_path))
monkeypatch.setenv("VLLM_OMNI_EXTERNAL_WORKER_ORT_CPU", FAKE_WORKER)
monkeypatch.setenv("VLLM_OMNI_EXTERNAL_PYTHON_ORT_CPU", sys.executable)
return launch.resolve(launch.ROUTE_CPU)
return configure
def _device(device_id: str, kind: str, formats, route: str, *, runnable: bool = True,
reason: str = "") -> DeviceCapability:
return DeviceCapability(
device_id=device_id,
kind=kind,
vendor="amd",
name=f"test {kind}",
backend="ort:cpu" if runnable else None,
runnable=runnable,
memory_pool="host_ram",
memory_bytes=32 * 2**30,
compute_capability=None,
weight_formats=frozenset(formats),
evidence="B" if runnable else "D",
reason=reason,
extra={"worker_route": route, "routes": [{"name": route, "available": runnable,
"reason": reason}]},
)
@pytest.fixture
def npu_device() -> DeviceCapability:
"""A16W8 only -- the real constraint, not a simplification."""
return _device("npu:amd", "npu", {FORMAT_ONNX_A16W8}, launch.ROUTE_CPU)
@pytest.fixture
def igpu_device() -> DeviceCapability:
return _device("igpu:amd", "gpu_integrated", {FORMAT_ONNX_FP16, FORMAT_ONNX_FP32},
launch.ROUTE_CPU)
@pytest.fixture
def unreachable_npu() -> DeviceCapability:
return _device(
"npu:amd", "npu", {FORMAT_ONNX_A16W8}, launch.ROUTE_VITISAI,
runnable=False,
reason="an MCDM device; WSL2 forwards display adapters only, so there is no device node here",
)
@pytest.fixture
def a16w8_graph(tmp_path) -> Path:
"""A file that stands in for an exported graph. Never loaded by ORT here."""
path = tmp_path / "stage.onnx"
path.write_bytes(b"not really onnx, and nothing in these tests parses it" * 64)
return path
+110
View File
@@ -0,0 +1,110 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
"""A stage worker that speaks the protocol and never touches a device.
Selected with ``VLLM_OMNI_EXTERNAL_WORKER_ORT_CPU``, so the client, the
framing, the placement gate and every refusal path are exercised on a machine
with no AMD hardware, no onnxruntime and no Windows. What it replies is read
from the JSON file named by ``VLLM_OMNI_FAKE_WORKER_JSON``:
``load`` body merged into the load reply -- set ``node_counts`` and
``fraction_on_target`` to stage a declined graph.
``run`` ``{"scale": float}``; outputs are the inputs times it.
``die_on`` op name after which the worker exits without replying, for the
"worker vanished mid-request" path.
"""
from __future__ import annotations
import importlib.util
import json
import os
import sys
from pathlib import Path
import numpy as np
_HERE = Path(__file__).resolve()
_PROTOCOL = (
_HERE.parents[4] / "vllm_omni" / "edge" / "local" / "external" / "protocol.py"
)
spec = importlib.util.spec_from_file_location("_fake_protocol", _PROTOCOL)
proto = importlib.util.module_from_spec(spec)
sys.modules["_fake_protocol"] = proto
spec.loader.exec_module(proto)
def main() -> int:
host, port, token = sys.argv[2], int(sys.argv[4]), sys.argv[6]
config = {}
config_path = os.environ.get("VLLM_OMNI_FAKE_WORKER_JSON")
if config_path and Path(config_path).is_file():
config = json.loads(Path(config_path).read_text())
import socket
sock = socket.create_connection((host, port), timeout=30)
proto.send_message(
sock,
proto.OP_HELLO,
{
"token": config.get("token", token),
"executable": sys.executable,
"python": sys.version,
"platform": sys.platform,
"pid": os.getpid(),
"onnxruntime": "fake",
"numpy": np.__version__,
"available_providers": ["CPUExecutionProvider"],
"rss_bytes": 1024,
},
)
while True:
op, body, tensors = proto.recv_message(sock)
if config.get("die_on") == op:
sock.close()
return 0
if op == proto.OP_LOAD:
reply = {
"ep": body.get("ep", "cpu"),
"session_providers": ["CPUExecutionProvider"],
"available_providers": ["CPUExecutionProvider"],
"node_counts": {"CPUExecutionProvider": 4},
"total_nodes": 4,
"target_nodes": 4,
"fraction_on_target": 1.0,
"session_create_s": 0.01,
"warmup_s": 0.001,
"rss_bytes": 111 * 2**20,
"inputs": [{"name": n, "type": "tensor(float)", "shape": list(t.shape)}
for n, t in tensors.items()],
"outputs": [{"name": "y", "type": "tensor(float)", "shape": []}],
}
reply.update(config.get("load", {}))
proto.send_message(sock, proto.OP_OK, reply)
elif op == proto.OP_RUN:
scale = float(config.get("run", {}).get("scale", 2.0))
proto.send_message(
sock,
proto.OP_OK,
{"run_s": 0.001},
{f"{k}_out": (v * scale) for k, v in tensors.items()},
)
elif op == proto.OP_STATS:
proto.send_message(
sock, proto.OP_OK,
{"runs": 1, "total_run_s": 0.001, "rss_bytes": 111 * 2**20,
"peak_rss_bytes": 122 * 2**20, "report": {}},
)
elif op == proto.OP_CLOSE:
proto.send_message(sock, proto.OP_OK, {})
return 0
else:
proto.send_message(sock, proto.OP_ERR,
{"message": f"unknown op {op}", "code": "ValueError"})
if __name__ == "__main__":
raise SystemExit(main())
+103
View File
@@ -0,0 +1,103 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
"""Starting, driving and losing a worker process."""
from __future__ import annotations
import numpy as np
import pytest
from vllm_omni.edge.local.external import launch
from vllm_omni.edge.local.external.client import ExternalWorker, WorkerStartError
def test_handshake_and_round_trip(fake_route):
with ExternalWorker(fake_route()) as worker:
assert worker.hello["onnxruntime"] == "fake"
report = worker.load("/nonexistent/stage.onnx", example_inputs={"x": np.ones(4, np.float32)})
assert report.fraction_on_target == 1.0
assert report.rss_bytes == 111 * 2**20
outputs, timing = worker.run({"x": np.ones(4, np.float32)})
assert np.array_equal(outputs["x_out"], np.full(4, 2.0, np.float32))
assert timing.round_trip_s >= timing.worker_s
assert timing.transport_s == pytest.approx(timing.round_trip_s - timing.worker_s)
assert worker.stats()["peak_rss_bytes"] == 122 * 2**20
def test_wrong_token_is_refused(fake_route):
"""The listener is on a host-visible address; a stray peer must not be served."""
worker = ExternalWorker(fake_route(token="not-the-token"))
with pytest.raises(WorkerStartError, match="wrong token"):
worker.start()
worker.close()
def test_worker_that_vanishes_mid_request_reports_rather_than_hangs(fake_route):
worker = ExternalWorker(fake_route(die_on="run"))
worker.start()
worker.load("/nonexistent/stage.onnx", example_inputs={"x": np.ones(2, np.float32)})
with pytest.raises(WorkerStartError, match="worker connection failed"):
worker.run({"x": np.ones(2, np.float32)})
worker.close()
def test_unavailable_route_refuses_at_construction():
route = launch.Route(
name="ort-vitisai", interpreter=None, worker="w.py", ep="vitisai",
is_windows=True, available=False, reason="no interpreter installed",
)
with pytest.raises(WorkerStartError, match="no interpreter installed"):
ExternalWorker(route)
def test_close_is_idempotent(fake_route):
worker = ExternalWorker(fake_route())
worker.start()
worker.close()
worker.close()
def test_bind_address_is_loopback_for_a_same_os_worker():
from vllm_omni.edge.local.external import client
assert client._bind_address(is_windows=False) == "127.0.0.1"
def test_bind_address_for_a_windows_worker_is_not_loopback_under_wsl():
"""The regression this exists for: probing the WSL nameserver instead of the
gateway yields 10.255.255.254, an address only this distro can reach, and
the Windows worker then dies with ECONNREFUSED after a silent start."""
from vllm_omni.edge.local.external import client
if not launch.is_wsl():
pytest.skip("not running under WSL interop")
assert not client._bind_address(is_windows=True).startswith(("127.", "10.255."))
def test_external_data_counts_toward_the_artifact_size(tmp_path):
"""An ONNX graph with external weights is a few MB of topology pointing at
gigabytes beside it. Charging only the .onnx told the admission ledger that
a 1.8 GB vision tower costs 2 MiB."""
import onnx
from onnx import helper, numpy_helper
from vllm_omni.edge.local.manifest import build_graph_artifact
weight = numpy_helper.from_array(np.zeros((256, 256), np.float32), name="w")
node = helper.make_node("MatMul", ["x", "w"], ["y"])
graph = helper.make_graph(
[node], "g",
[helper.make_tensor_value_info("x", onnx.TensorProto.FLOAT, [1, 256])],
[helper.make_tensor_value_info("y", onnx.TensorProto.FLOAT, [1, 256])],
[weight],
)
path = tmp_path / "m.onnx"
onnx.save(helper.make_model(graph), str(path), save_as_external_data=True,
all_tensors_to_one_file=True, location="m.onnx.data")
artifact = build_graph_artifact(path, fmt="onnx:fp32", opset=21, source_model="t",
component="c", exporter="e")
assert artifact.bytes > path.stat().st_size
assert artifact.bytes >= 256 * 256 * 4
+94
View File
@@ -0,0 +1,94 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
"""The wire format, which has to survive a peer that is not us."""
from __future__ import annotations
import socket
import threading
import numpy as np
import pytest
from vllm_omni.edge.local.external import protocol
def _round_trip(op, body=None, tensors=None):
near, far = socket.socketpair()
try:
threading.Thread(
target=lambda: protocol.send_message(near, op, body, tensors), daemon=True
).start()
return protocol.recv_message(far)
finally:
near.close()
far.close()
def test_tensors_survive_dtype_and_shape():
sent = {
"f32": np.arange(12, dtype=np.float32).reshape(3, 4),
"i64": np.array([[1, 2], [3, 4]], dtype=np.int64),
"u16": np.array([7, 8, 9], dtype=np.uint16),
"scalar": np.array(3.5, dtype=np.float64),
}
op, body, got = _round_trip(protocol.OP_RUN, {"n": 1}, sent)
assert op == protocol.OP_RUN and body == {"n": 1}
for name, array in sent.items():
assert got[name].dtype == array.dtype
assert got[name].shape == array.shape
assert np.array_equal(got[name], array)
def test_received_tensors_are_writable():
"""``frombuffer`` hands back a read-only view aliasing the socket buffer.
ORT's IOBinding writes into the arrays it is given, so a read-only result
would fail at the far end of a working connection rather than here.
"""
_, _, got = _round_trip(protocol.OP_RUN, {}, {"x": np.ones(4, dtype=np.float32)})
got["x"][0] = 5.0 # must not raise
assert got["x"][0] == 5.0
def test_payload_larger_than_one_recv():
"""Stream sockets short-read; a naive recv would misparse the next tensor."""
big = np.arange(4 * 1024 * 1024, dtype=np.float32)
_, _, got = _round_trip(protocol.OP_RUN, {}, {"big": big, "after": np.array([1.0])})
assert np.array_equal(got["big"], big)
assert np.array_equal(got["after"], np.array([1.0]))
def test_empty_message_and_no_tensors():
op, body, got = _round_trip(protocol.OP_STATS)
assert (op, body, got) == (protocol.OP_STATS, {}, {})
def test_error_reply_raises_with_remote_detail():
with pytest.raises(protocol.WorkerError) as excinfo:
_round_trip(protocol.OP_ERR, {"message": "boom", "code": "ValueError",
"traceback": "far side traceback"})
assert excinfo.value.code == "ValueError"
assert "far side traceback" in excinfo.value.remote_traceback
def test_closed_peer_is_a_protocol_error_not_a_hang():
near, far = socket.socketpair()
near.close()
with pytest.raises(protocol.ProtocolError):
protocol.recv_message(far)
far.close()
def test_oversized_header_is_refused_before_allocation():
"""A corrupt length must not become a multi-gigabyte allocation."""
near, far = socket.socketpair()
try:
import struct
near.sendall(struct.pack(">I", protocol.MAX_HEADER_BYTES + 1))
with pytest.raises(protocol.ProtocolError, match="over the limit"):
protocol.recv_message(far)
finally:
near.close()
far.close()
+209
View File
@@ -0,0 +1,209 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
"""Placing a stage on an external device, and refusing to.
The gate tested here is the one that keeps a CPU fallback from being reported
as NPU execution. It cannot be replaced by a cheaper check: a VitisAI session
lists the EP in ``get_providers()`` whether or not it claimed a node, and a
graph it declined runs on the CPU and returns bit-identical numbers. So these
tests assert on node assignments, never on output values.
"""
from __future__ import annotations
import numpy as np
import pytest
from vllm_omni.edge.local.capabilities import FORMAT_ONNX_A16W8, FORMAT_ONNX_FP16
from vllm_omni.edge.local.external.stage import (
ExternalStage,
PlacementRefused,
plan_external_stage,
verify_placement,
)
from vllm_omni.edge.local.manifest import build_graph_artifact
from vllm_omni.edge.local.plan import (
REFUSE_EP_PLACEMENT,
REFUSE_NO_ARTIFACT,
REFUSE_NO_DEVICE,
REFUSE_ROUTE,
)
def _artifact(path, fmt=FORMAT_ONNX_A16W8, component="stage"):
return build_graph_artifact(
path, fmt=fmt, opset=21, source_model="test", component=component,
exporter="tests.edge.local.external",
)
def test_a16w8_graph_is_placed_on_the_npu(a16w8_graph, npu_device, igpu_device):
plan = plan_external_stage(_artifact(a16w8_graph), [igpu_device, npu_device])
assert plan.admitted
assert plan.device is not None and plan.device.device_id == "npu:amd"
# The iGPU was considered and rejected on format; the record says so rather
# than only naming the winner.
assert [r.code for r in plan.refusals] == [REFUSE_NO_ARTIFACT]
def test_fp16_graph_is_refused_by_the_npu_not_quietly_downgraded(a16w8_graph, npu_device):
"""A16W8 is the only door on XDNA2, and the failure mode for anything else
is silent: no error, every node on the CPU. So it is refused at plan time."""
plan = plan_external_stage(_artifact(a16w8_graph, fmt=FORMAT_ONNX_FP16), [npu_device])
assert not plan.admitted
assert plan.refusals[0].code == REFUSE_NO_ARTIFACT
assert "a16w8" in plan.refusals[0].remedy.lower()
def test_require_refuses_rather_than_substituting(a16w8_graph, npu_device, igpu_device):
""""Does the NPU run this" must not be answered with the iGPU."""
plan = plan_external_stage(
_artifact(a16w8_graph, fmt=FORMAT_ONNX_FP16), [npu_device, igpu_device],
require="npu:amd",
)
assert not plan.admitted
assert {r.device_id for r in plan.refusals} == {"npu:amd"}
def test_prefer_falls_through(a16w8_graph, npu_device, igpu_device):
plan = plan_external_stage(
_artifact(a16w8_graph, fmt=FORMAT_ONNX_FP16), [npu_device, igpu_device],
prefer="npu:amd",
)
assert plan.admitted and plan.device.device_id == "igpu:amd"
def test_unreachable_device_refuses_with_the_route_reason(a16w8_graph, unreachable_npu):
plan = plan_external_stage(_artifact(a16w8_graph), [unreachable_npu])
assert not plan.admitted
assert plan.refusals[0].code == REFUSE_ROUTE
assert "MCDM" in plan.refusals[0].message
assert "VLLM_OMNI_EXTERNAL_PYTHON_ORT_VITISAI" in plan.refusals[0].remedy
def test_no_external_device_at_all(a16w8_graph):
plan = plan_external_stage(_artifact(a16w8_graph), [])
assert not plan.admitted and plan.refusals[0].code == REFUSE_NO_DEVICE
def test_required_device_absent_from_enumeration(a16w8_graph, igpu_device):
plan = plan_external_stage(_artifact(a16w8_graph), [igpu_device], require="npu:amd")
assert not plan.admitted and plan.refusals[0].code == REFUSE_NO_DEVICE
def test_budget_is_on_the_shared_pool(a16w8_graph, npu_device):
plan = plan_external_stage(_artifact(a16w8_graph), [npu_device])
assert {r.pool for r in plan.reservations} == {"host_ram"}
assert plan.budget_bytes > 0
def test_open_verifies_placement_and_closes_the_ledger(a16w8_graph, npu_device, fake_route, tmp_path):
fake_route()
plan = plan_external_stage(_artifact(a16w8_graph), [npu_device])
with ExternalStage(plan) as stage:
report = stage.open({"x": np.ones(4, np.float32)}, profile_dir=tmp_path)
assert report.fraction_on_target == 1.0
runtime = next(r for r in plan.reservations if r.purpose == "worker runtime")
assert runtime.actual_upper_bound_bytes == 111 * 2**20
assert runtime.bytes >= runtime.actual_upper_bound_bytes, "budget must bound the measurement"
def test_declined_graph_is_refused_even_though_it_ran(a16w8_graph, npu_device, fake_route, tmp_path):
"""The whole point: it produced correct output, on the CPU."""
fake_route(load={"node_counts": {"CPUExecutionProvider": 9, "vitisai": 1},
"total_nodes": 10, "target_nodes": 1, "fraction_on_target": 0.1})
plan = plan_external_stage(_artifact(a16w8_graph), [npu_device])
stage = ExternalStage(plan)
with pytest.raises(PlacementRefused) as excinfo:
stage.open({"x": np.ones(4, np.float32)}, profile_dir=tmp_path)
assert excinfo.value.refusal.code == REFUSE_EP_PLACEMENT
assert "1 of 10" in excinfo.value.refusal.message
assert "Light" in excinfo.value.refusal.remedy
def test_unverified_placement_is_refused_not_assumed(a16w8_graph, npu_device, fake_route, tmp_path):
"""``None`` means nobody looked. It must not be rounded to "fine"."""
fake_route(load={"fraction_on_target": None, "node_counts": {},
"placement_unknown_reason": "no profiled run"})
plan = plan_external_stage(_artifact(a16w8_graph), [npu_device])
stage = ExternalStage(plan)
with pytest.raises(PlacementRefused) as excinfo:
stage.open({"x": np.ones(4, np.float32)}, profile_dir=tmp_path)
assert excinfo.value.refusal.code == REFUSE_EP_PLACEMENT
assert "not measured" in excinfo.value.refusal.message
def test_open_without_example_inputs_is_a_usage_error(a16w8_graph, npu_device, fake_route):
fake_route()
plan = plan_external_stage(_artifact(a16w8_graph), [npu_device])
stage = ExternalStage(plan)
with pytest.raises(ValueError, match="example_inputs are required"):
stage.open({})
stage.close()
def test_verify_placement_accepts_a_real_split(a16w8_graph, npu_device):
from vllm_omni.edge.local.external.client import LoadReport
plan = plan_external_stage(_artifact(a16w8_graph), [npu_device])
plan.min_fraction_on_target = 0.3
report = LoadReport(ep="vitisai", graph_path="g.onnx", total_nodes=3, target_nodes=1,
fraction_on_target=1 / 3, node_counts={"vitisai": 1, "CPUExecutionProvider": 2})
assert verify_placement(plan, report) is None
def test_refusing_a_plan_cannot_be_opened(a16w8_graph, npu_device):
plan = plan_external_stage(_artifact(a16w8_graph, fmt=FORMAT_ONNX_FP16), [npu_device])
with pytest.raises(PlacementRefused):
ExternalStage(plan)
def test_a_masked_device_is_told_to_drop_the_mask(a16w8_graph, npu_device):
"""The remedy has to name the cause the caller actually has.
A masked device and a device WSL cannot forward are both "unreachable", and
explaining MCDM forwarding to somebody who simply passed ``--mask npu``
sends them after a problem they do not have.
"""
import dataclasses
masked = dataclasses.replace(npu_device, runnable=False, masked=True,
backend=None, reason="masked out by --mask (npu)")
plan = plan_external_stage(_artifact(a16w8_graph), [masked])
assert not plan.admitted
assert plan.refusals[0].code == REFUSE_ROUTE
assert "--mask" in plan.refusals[0].remedy
assert "MCDM" not in plan.refusals[0].remedy
def test_a_stage_larger_than_the_shared_pool_is_refused(a16w8_graph, npu_device):
plan = plan_external_stage(_artifact(a16w8_graph), [npu_device], pool_capacity_bytes=1)
assert not plan.admitted
from vllm_omni.edge.local.plan import REFUSE_CAPACITY
assert plan.refusals[0].code == REFUSE_CAPACITY
assert "same pool the CPU stage is budgeted against" in plan.refusals[0].message
def test_a_silently_swapped_provider_is_refused_by_name(a16w8_graph, npu_device, fake_route, tmp_path):
"""onnxruntime does not raise when a provider fails to initialise.
It prints "Falling back to ['CPUExecutionProvider'] and retrying" and hands
back a working CPU session — which is how a 27B vision tower ran end to end
on the CPU here while the caller believed it was on the iGPU. The report
carries the swap, and it outranks the node count because "the provider
never initialised" says what to fix and "0 of 1171 nodes" does not.
"""
fake_route(load={
"session_providers": ["CPUExecutionProvider"],
"requested_provider_missing": "DmlExecutionProvider",
"fallback_note": "DmlExecutionProvider failed to initialise and onnxruntime silently fell back",
"node_counts": {"CPUExecutionProvider": 113},
"total_nodes": 113, "target_nodes": 0, "fraction_on_target": 0.0,
})
plan = plan_external_stage(_artifact(a16w8_graph), [npu_device])
stage = ExternalStage(plan)
with pytest.raises(PlacementRefused) as excinfo:
stage.open({"x": np.ones(4, np.float32)}, profile_dir=tmp_path)
assert excinfo.value.refusal.code == REFUSE_EP_PLACEMENT
assert "silently fell back" in excinfo.value.refusal.message
+64
View File
@@ -0,0 +1,64 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
"""Shape arithmetic for the exported vision tower.
The tower itself needs a 29 GB checkpoint, so what is covered here is the part
that decides whether an export is even well-formed — and that is where a silent
mistake would land: a grid that does not divide by the merge size produces a
graph that exports, runs, and returns the wrong number of tokens to the LLM.
"""
from __future__ import annotations
import json
import pytest
from vllm_omni.edge.local.artifacts.vision_tower import tower_shape
VISION_CONFIG = {
"depth": 27, "hidden_size": 1152, "in_channels": 3, "intermediate_size": 4304,
"num_heads": 16, "num_position_embeddings": 2304, "out_hidden_size": 5120,
"patch_size": 16, "spatial_merge_size": 2, "temporal_patch_size": 2,
}
@pytest.fixture
def checkpoint(tmp_path):
(tmp_path / "config.json").write_text(json.dumps({"vision_config": VISION_CONFIG}))
return tmp_path
def test_448_gives_784_patches_and_196_tokens(checkpoint):
shape = tower_shape(checkpoint, 448)
assert (shape.grid_h, shape.grid_w) == (28, 28)
assert shape.patches == 784
# 3 channels x 2 temporal x 16 x 16
assert shape.patch_dim == 1536
# 784 patches merged 2x2
assert shape.merged_tokens == 196
assert shape.out_hidden_size == 5120
def test_image_size_must_divide_by_the_patch_size(checkpoint):
with pytest.raises(ValueError, match="multiple of patch_size"):
tower_shape(checkpoint, 450)
def test_grid_must_divide_by_the_spatial_merge(checkpoint):
"""A 3x3 grid of patches cannot be merged 2x2. Exporting it anyway would
hand the language model a silently wrong number of image tokens."""
with pytest.raises(ValueError, match="spatial_merge_size"):
tower_shape(checkpoint, 48)
def test_a_checkpoint_without_a_tower_is_refused(tmp_path):
(tmp_path / "config.json").write_text(json.dumps({"model_type": "spark2_5"}))
with pytest.raises(ValueError, match="no vision_config"):
tower_shape(tmp_path, 448)
@pytest.mark.parametrize("size,patches,tokens", [(224, 196, 49), (448, 784, 196), (896, 3136, 784)])
def test_token_count_scales_with_area(checkpoint, size, patches, tokens):
shape = tower_shape(checkpoint, size)
assert (shape.patches, shape.merged_tokens) == (patches, tokens)
+106
View File
@@ -0,0 +1,106 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
"""[W4] The native-Windows vLLM route, and why it is refused.
``win-cuda`` is the first route whose far side is torch rather than
onnxruntime, and the first that exists to leave WSL rather than to reach a
device WSL cannot see. Declaring it makes a Windows engine a row in the route
table instead of a parallel universe.
It is also the first route that **cannot pass the placement gate**, and these
tests pin that down so nobody later mistakes the refusal for a bug. M3 made a
measured device attribution a hard admission condition after a VitisAI session
listed its EP, claimed zero nodes, and returned output bit-identical to the
CPU's. vLLM emits no per-operation device map, so a ``win-cuda`` worker has
nothing of that kind to report -- and the rule is about evidence, not about
whose code it is, so our own engine is refused on it exactly as the NPU is.
"""
from __future__ import annotations
import numpy as np
import pytest
from vllm_omni.edge.local.capabilities import FORMAT_ONNX_A16W8
from vllm_omni.edge.local.external import launch
from vllm_omni.edge.local.external.stage import (
ExternalStage,
PlacementRefused,
plan_external_stage,
)
from vllm_omni.edge.local.manifest import build_graph_artifact
from vllm_omni.edge.local.plan import REFUSE_EP_PLACEMENT, REFUSE_NO_DEVICE
from .conftest import _device
def _artifact(path):
return build_graph_artifact(
path, fmt=FORMAT_ONNX_A16W8, opset=21, source_model="test",
component="stage", exporter="tests.edge.local.external",
)
def test_win_cuda_is_a_known_route():
"""It resolves through the same machinery as every other route."""
route = launch.resolve(launch.ROUTE_WIN_CUDA)
assert route.name == "win-cuda"
assert route.ep == "cuda"
# It needs a native-Windows interpreter, like the two AMD Windows routes.
assert route.is_windows is True
# Available or not is environment-dependent; a reason is not.
assert route.available or route.reason
def test_win_cuda_reports_no_placement_evidence():
"""The constant is the contract: ``None`` means nobody can look yet.
Asserted rather than assumed, because the tempting edit -- setting it to
1.0 because the worker "obviously" runs on the GPU -- is exactly the
reasoning M3 disproved.
"""
assert launch.WIN_CUDA_PLACEMENT_EVIDENCE is None
def test_unverified_placement_is_refused_for_our_own_engine(a16w8_graph, fake_route, tmp_path):
"""A worker that cannot say where it ran is refused, not trusted.
The fake worker stands in for a ``win-cuda`` one: it runs, it returns
correct-looking numbers, and it reports ``fraction_on_target=None`` because
vLLM has no per-op device map to derive one from. That is precisely the
shape of a silent CPU fallback, so it must not be admitted.
"""
fake_route(load={
"fraction_on_target": None,
"node_counts": {},
"placement_unknown_reason": "vllm emits no per-operation device map",
})
device = _device("npu:amd", "npu", [FORMAT_ONNX_A16W8], launch.ROUTE_CPU)
plan = plan_external_stage(_artifact(a16w8_graph), [device])
stage = ExternalStage(plan)
with pytest.raises(PlacementRefused) as excinfo:
stage.open({"x": np.ones(4, np.float32)}, profile_dir=tmp_path)
assert excinfo.value.refusal.code == REFUSE_EP_PLACEMENT
assert "not measured" in excinfo.value.refusal.message
def test_external_planner_does_not_yet_admit_a_discrete_gpu(a16w8_graph, fake_route):
"""A documented gap, pinned so the next person does not rediscover it.
``plan_external_stage`` filters candidates to ``("gpu_integrated", "npu")``
(``stage.py``). Every external route so far reaches a device WSL cannot see
*and* that is integrated or an NPU, so the filter was exactly right. A
``win-cuda`` route breaks that coupling: its device is a **discrete** GPU
reached out-of-process for an OS reason, not a visibility one.
This test asserts the current refusal rather than a desired behaviour. When
the planner learns about externally-routed discrete GPUs, this test should
fail and be rewritten -- that failure is the signal, not a regression.
"""
fake_route()
device = _device("cuda:0", "gpu_discrete", [FORMAT_ONNX_A16W8], launch.ROUTE_CPU)
plan = plan_external_stage(_artifact(a16w8_graph), [device])
assert plan.device is None
assert plan.refusals
assert plan.refusals[0].code == REFUSE_NO_DEVICE
assert "integrated GPU or NPU" in plan.refusals[0].message
+174
View File
@@ -0,0 +1,174 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
"""What this process can run on, as opposed to what is plugged in."""
import pytest
from vllm_omni.edge.hardware_probe import ACCEL_GPU_DISCRETE
from vllm_omni.edge.local.capabilities import (
FORMAT_DENSE,
FORMAT_FP8,
FORMAT_GPTQ,
FORMAT_INT8,
FORMAT_NVFP4,
MASK_ENV,
cuda_weight_formats,
enumerate_devices,
parse_mask,
runs_exported_graphs,
)
from .conftest import blackwell_laptop, cpu_only_box
pytestmark = [pytest.mark.core_model, pytest.mark.cpu]
def _by_id(devices):
return {d.device_id: d for d in devices}
# ---------------------------------------------------------- format gating
def test_blackwell_has_no_int8_path():
"""sm_120 is inside the SM >= 100 range where cutlass c3x has no int8
scaled_mm. This is the single fact that turns a 40-second crash into a
30-millisecond refusal, so it gets its own test."""
formats = cuda_weight_formats((12, 0))
assert FORMAT_INT8 not in formats
assert FORMAT_FP8 in formats
assert FORMAT_NVFP4 in formats
def test_ampere_keeps_int8_and_has_no_nvfp4():
formats = cuda_weight_formats((8, 6))
assert FORMAT_INT8 in formats
assert FORMAT_NVFP4 not in formats
assert FORMAT_FP8 not in formats
def test_dense_runs_on_every_cuda_generation():
for capability in ((7, 5), (8, 0), (9, 0), (12, 0)):
assert FORMAT_DENSE in cuda_weight_formats(capability)
# ------------------------------------------------------------ runnability
def test_a_cuda_wheel_cannot_drive_the_cpu_and_says_so():
devices = _by_id(enumerate_devices(blackwell_laptop(), platform_device_type="cuda"))
assert devices["cuda:0"].runnable
assert not devices["cpu"].runnable
assert "omni-cpu" in devices["cpu"].reason
def test_a_cpu_wheel_cannot_drive_the_card_and_says_so():
devices = _by_id(enumerate_devices(blackwell_laptop(), platform_device_type="cpu"))
assert devices["cpu"].runnable
assert not devices["cuda:0"].runnable
assert "omni-cuda" in devices["cuda:0"].reason
def test_the_igpu_and_npu_are_reported_not_dropped():
"""'The machine has an NPU' and 'a stage can run on it' are different
claims; the plan has to be able to show which one it relied on.
Both are now reachable (M3), through a worker in another interpreter, so
the invariant is no longer "never runnable" -- it is that the record always
says which of the two claims it is making, and never leaves a caller to
guess.
"""
devices = _by_id(enumerate_devices(blackwell_laptop(), platform_device_type="cuda"))
assert "npu:amd" in devices
assert "gpu_integrated:amd" in devices
for key in ("npu:amd", "gpu_integrated:amd"):
device = devices[key]
assert device.evidence in ("B", "D")
if device.runnable:
assert device.backend, "a runnable device must name the backend that drives it"
assert device.extra["worker_route"], "and the route it was resolved through"
else:
assert device.reason, "and an unrunnable one must say why"
assert device.backend is None
# Either way these execute exported graphs, never a checkpoint.
assert runs_exported_graphs(device)
def test_the_amd_devices_refuse_with_the_missing_interpreter_named(monkeypatch):
"""A device that works and a venv that is not installed are different
problems; the reason has to distinguish them well enough to act on."""
for route in ("ORT_VITISAI", "ORT_DML", "TORCH_DML"):
monkeypatch.setenv(f"VLLM_OMNI_EXTERNAL_PYTHON_{route}", "/nonexistent/python")
devices = _by_id(enumerate_devices(blackwell_laptop(), platform_device_type="cuda"))
for key in ("npu:amd", "gpu_integrated:amd"):
device = devices[key]
assert not device.runnable and device.backend is None
assert "/nonexistent/python" in device.reason or "native-Windows" in device.reason
def test_the_amd_devices_get_no_memory_budget_of_their_own():
"""Section 6: the iGPU and the NPU allocate out of the CPU's RAM.
Carrying the pool size on their rows would let a caller add three copies of
the same memory together, so the number lives on the host row only and the
stage planner reads it from there.
"""
devices = _by_id(enumerate_devices(blackwell_laptop(), platform_device_type="cpu"))
for key in ("npu:amd", "gpu_integrated:amd"):
assert devices[key].memory_bytes == 0
assert devices[key].memory_pool == "host_ram"
assert devices[key].extra["host_pool_bytes"] > 0
def test_a_cpu_only_box_reports_no_cuda_row_at_all():
"""A masked GPU and an absent GPU are different situations and must not
produce the same record."""
devices = _by_id(enumerate_devices(cpu_only_box(), platform_device_type="cpu"))
assert "cuda:0" not in devices
assert devices["cpu"].runnable
# ------------------------------------------------------------------ masking
def test_masking_disables_without_hiding():
devices = _by_id(enumerate_devices(
blackwell_laptop(), mask=frozenset({ACCEL_GPU_DISCRETE}), platform_device_type="cuda"
))
gpu = devices["cuda:0"]
assert gpu.masked and not gpu.runnable
# Still enumerated, with its real memory: a mask is a policy, not an
# amnesia, and the record has to show the card was there.
assert gpu.memory_bytes > 0
assert "mask" in gpu.reason
def test_mask_is_read_from_the_environment(monkeypatch):
monkeypatch.setenv(MASK_ENV, "gpu_discrete, cpu")
assert parse_mask() == frozenset({"gpu_discrete", "cpu"})
monkeypatch.delenv(MASK_ENV)
assert parse_mask() == frozenset()
def test_an_explicit_mask_beats_the_environment(monkeypatch):
monkeypatch.setenv(MASK_ENV, "gpu_discrete")
assert parse_mask("") == frozenset()
# ---------------------------------------------------------------- pooling
def test_cpu_and_accelerators_share_one_host_pool():
"""Section 6 forbids giving the iGPU and the NPU each their own RAM."""
devices = enumerate_devices(blackwell_laptop(), platform_device_type="cpu")
host_pool = [d for d in devices if d.memory_pool == "host_ram"]
assert {d.device_id for d in host_pool} >= {"cpu", "npu:amd", "gpu_integrated:amd"}
# Only the CPU row carries the bytes; the others are 0 so nothing can add
# three copies of the same RAM together.
assert sum(d.memory_bytes for d in host_pool) == next(
d.memory_bytes for d in host_pool if d.device_id == "cpu"
)
def test_the_discrete_gpu_has_its_own_pool():
devices = _by_id(enumerate_devices(blackwell_laptop(), platform_device_type="cuda"))
assert devices["cuda:0"].memory_pool == "vram"
assert devices["cpu"].memory_pool == "host_ram"
def test_cpu_weight_formats_include_int8_on_x86():
devices = _by_id(enumerate_devices(blackwell_laptop(), platform_device_type="cpu"))
assert FORMAT_INT8 in devices["cpu"].weight_formats
assert FORMAT_GPTQ in devices["cpu"].weight_formats
+279
View File
@@ -0,0 +1,279 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
"""End to end: the M0 acceptance criteria, executed against a real checkpoint.
This is the test that says the local text mode works, so it tests the thing the
roadmap actually asks for rather than a proxy for it:
* both startups -- device-visible and capability-masked -- reach a decision,
and a refusal is a pass, because "选择兼容方案或明确拒绝" is an either/or;
* the same fixed set of twelve prompts, each generating at least 128 tokens;
* TTFT and decode rate recorded per request;
* the budgeted peak is an upper bound on the measured one, and nothing OOMs;
* cancellation releases, and no event from the retired epoch is delivered.
It needs real weights and a real backend, so it skips rather than fails when
there is no checkpoint. Which one it runs is whatever this interpreter can
drive: the CUDA venv gets the bf16 build, the CPU venv gets the int8 one --
which is itself the point, since the int8 build is the one the CUDA plan
refuses. Override with ``VLLM_OMNI_LOCAL_TEST_MODEL``.
Roughly a minute on the reference laptop's GPU and three on its CPU. Marked
``local_model`` because it is not a unit test and should not run in a PR gate.
"""
from __future__ import annotations
import os
from pathlib import Path
import pytest
import pytest_asyncio
from vllm_omni.edge.local import (
LocalTextEngine,
PlanNotAdmitted,
acceptance_prompts,
plan_text_session,
)
from vllm_omni.edge.local.capabilities import FORMAT_INT8
# One event loop for the whole module. The engine fixture is module-scoped --
# loading 7.7 GB per test would be absurd -- and the asyncio primitives inside
# AsyncOmni belong to whichever loop created them. Leaving the tests on
# pytest-asyncio's default per-function loop means a cancel awaits a task whose
# backend cleanup lives on a different, no-longer-running loop, and it hangs
# there rather than failing.
pytestmark = [pytest.mark.local_model, pytest.mark.asyncio(loop_scope="module")]
MIN_TOKENS = 128
MAX_MODEL_LEN = 4096
# Checkpoints under the repo's models/ directory, by the platform that can run
# them. The int8 build is deliberately the CPU entry: Blackwell refuses it.
_CANDIDATES = {
"cuda": ("Spark-X2.5-4B", "Spark-X2.5-1.7B-int8"),
"cpu": ("Spark-X2.5-1.7B-int8", "Spark-X2.5-4B"),
}
def _models_root() -> Path:
# tests/edge/local/ -> vllm-omni/ -> the workspace that holds models/
return Path(__file__).resolve().parents[3].parent / "models"
def _platform() -> str:
from vllm.platforms import current_platform
return str(getattr(current_platform, "device_type", "") or "")
def _find_model() -> str:
override = os.environ.get("VLLM_OMNI_LOCAL_TEST_MODEL")
if override:
return override
root = _models_root()
for name in _CANDIDATES.get(_platform(), ()):
if (root / name / "config.json").is_file():
return str(root / name)
pytest.skip(
f"no Spark checkpoint for platform {_platform()!r} under {root}; "
"set VLLM_OMNI_LOCAL_TEST_MODEL to run this"
)
@pytest.fixture(scope="module")
def model_dir() -> str:
return _find_model()
@pytest.fixture(scope="module")
def plan(model_dir: str):
p = plan_text_session(model_dir, max_model_len=MAX_MODEL_LEN, max_num_seqs=1)
if not p.admitted:
pytest.skip(f"this host cannot run {model_dir}:\n{p.summary()}")
return p
@pytest_asyncio.fixture(scope="module", loop_scope="module")
async def engine(plan):
eng = LocalTextEngine(plan)
await eng.start()
try:
yield eng
finally:
await eng.close()
# ------------------------------------------------------------------ planning
def test_the_masked_startup_reaches_a_decision(model_dir):
"""The no-NVIDIA class must produce a plan or an explicit refusal -- never
a crash and never a silent substitution."""
masked = plan_text_session(
model_dir, max_model_len=MAX_MODEL_LEN, mask=frozenset({"gpu_discrete"})
)
if masked.admitted:
assert masked.selected.memory_pool == "host_ram"
assert masked.selected.kind != "gpu_discrete"
else:
assert masked.refusals
assert all(r.message and r.remedy for r in masked.refusals)
assert any("mask" in r.message for r in masked.refusals) or _platform() != "cuda"
def test_a_refused_plan_cannot_be_started(model_dir):
refused = plan_text_session(
model_dir, max_model_len=MAX_MODEL_LEN, mask=frozenset({"gpu_discrete", "cpu"})
)
assert not refused.admitted
with pytest.raises(PlanNotAdmitted):
LocalTextEngine(refused)
@pytest.mark.skipif(
not (_models_root() / "Spark-X2.5-1.7B-int8" / "config.json").is_file(),
reason="the int8 checkpoint is not present",
)
def test_int8_is_refused_on_cuda_and_admitted_on_cpu():
"""The refusal and its remedy, checked against the real checkpoint on
whichever backend this interpreter has."""
int8 = str(_models_root() / "Spark-X2.5-1.7B-int8")
p = plan_text_session(int8, max_model_len=MAX_MODEL_LEN)
assert p.manifest.weight_format == FORMAT_INT8
if _platform() == "cuda":
assert not p.admitted
formats = [r for r in p.refusals if r.code == "weight_format_unsupported"]
assert formats and "omni-cpu" in formats[0].remedy
else:
assert p.admitted
assert p.selected.device_id == "cpu"
# ------------------------------------------------------------------- loading
async def test_the_engine_loads_and_reports_where_it_landed(engine):
assert engine.load_seconds and engine.load_seconds > 0
placement = engine.report_placement()
configured = placement["configured"]
assert "error" not in configured
# Read back from the stage's own config, not echoed from the plan.
assert configured["device_type"] == _platform()
assert configured["max_model_len"] == MAX_MODEL_LEN
assert configured["enforce_eager"] is True
async def test_the_kv_pool_is_the_size_the_plan_asked_for(engine, plan):
"""An absolute budget, honoured -- not whatever was left inside a
utilisation fraction."""
configured = engine.report_placement()["configured"]
assert configured["kv_cache_memory_bytes"] == plan.kv_budget.bytes_total
# ---------------------------------------------------------- the twelve prompts
async def test_twelve_prompts_each_reach_128_tokens(engine):
prompts = acceptance_prompts()
assert len(prompts) == 12
records = []
for name, text in prompts:
session = engine.open_session()
request_id, stream = await engine.submit(
session, text, max_tokens=MIN_TOKENS, temperature=0.0, ignore_eos=True
)
seqs = []
async for event in stream:
if event.kind == "token":
seqs.append(event.seq)
assert event.epoch == session.epoch
assert event.error is None, f"{name}: {event.error}"
record = engine.records[request_id]
engine.close_session(session.session_id)
assert record.finished, f"{name} did not finish"
assert record.output_tokens >= MIN_TOKENS, f"{name} produced {record.output_tokens}"
assert record.ttft_s is not None and record.ttft_s > 0
assert record.decode_tok_per_s is not None and record.decode_tok_per_s > 0
# Incremental, in order, no repeats: seq is what detects a lost chunk.
assert seqs == sorted(seqs)
assert len(seqs) == len(set(seqs))
records.append(record)
# The long prompt crosses the 512 sliding window many times; if window
# rollover were broken it would be broken here and not on the short ones.
long_record = next(r for r in records if r.prompt_tokens and r.prompt_tokens > 2000)
assert long_record.output_tokens >= MIN_TOKENS
async def test_the_budget_bounded_the_measured_peak(engine, plan):
"""Admission's whole claim: the plan's number is an upper bound, proven
before anything allocated."""
measured = engine.measured_peak()
assert measured["budgeted_peak_bytes"] == plan.peak_bytes
attributable = measured["attributable_peak_bytes"]
assert attributable is not None and attributable > 0
assert attributable <= measured["budgeted_peak_bytes"], (
f"measured {attributable / 2**30:.2f} GiB exceeded the budgeted "
f"{measured['budgeted_peak_bytes'] / 2**30:.2f} GiB"
)
async def test_usage_separates_what_was_measured_from_what_was_estimated(engine):
usage = engine.report_usage()
by_purpose = {r["purpose"]: r for r in usage["reservations"]}
assert by_purpose["weights"]["evidence"] == "D"
assert by_purpose["kv_cache"]["evidence"] == "E"
# Nothing gets an actual it cannot support: only the weights line is
# bounded by a counter on this host.
bounded = [p for p, r in by_purpose.items() if r["actual_upper_bound_bytes"]]
assert bounded == ["weights"]
# ------------------------------------------------------------- cancellation
async def test_cancel_releases_and_delivers_nothing_from_the_retired_epoch(engine):
session = engine.open_session()
request_id, stream = await engine.submit(
session, acceptance_prompts()[0][1], max_tokens=4096, ignore_eos=True
)
seen = 0
async for event in stream:
if event.kind == "token":
seen += 1
if seen >= 8:
break
assert seen >= 8
report = await engine.cancel(request_id)
assert report["aborted_in_backend"]
assert report["producer_stopped"], "the producer task did not unwind"
assert report["inflight_after"] == 0
# The session's state is retired, not reused.
assert report["session_epoch_now"] == session.epoch + 1
leaked = []
while True:
event = await stream.get()
if event is None:
break
leaked.append(event)
assert leaked == [], f"{len(leaked)} events escaped the retired epoch"
async def test_a_retired_handle_cannot_be_resubmitted(engine):
session = engine.open_session()
request_id, stream = await engine.submit(session, "Hello", max_tokens=32)
async for _ in stream:
break
await engine.cancel(request_id)
with pytest.raises(RuntimeError, match="stale"):
await engine.submit(session, "Hello again", max_tokens=8)
async def test_the_engine_still_generates_after_a_cancel(engine):
"""A cancelled request must not poison the engine for the next one."""
session = engine.open_session()
request_id, stream = await engine.submit(
session, "The capital of Australia is", max_tokens=16, ignore_eos=True
)
async for _ in stream:
pass
record = engine.records[request_id]
assert record.finished and record.output_tokens >= 16
+71
View File
@@ -0,0 +1,71 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
"""The placement report must measure per-process GPU attribution, not assume it.
[edge-infer W4] The W1 acceptance on native Windows carried a hardcoded "under
WSL2" explanation for an empty NVML process list. These tests pin the repaired
behaviour: the reason names the host it actually ran on, and a successful
attribution (NVML lists one of our PIDs) is reported as data, not a reason.
"""
from __future__ import annotations
import builtins
import sys
import types
import pytest
from vllm_omni.edge.local import engine
def test_host_kind_is_one_of_the_three_hosts():
assert engine._host_kind() in {"windows", "wsl2", "linux"}
def test_reason_names_the_host_when_nvml_is_unavailable(monkeypatch):
real_import = builtins.__import__
def no_pynvml(name, *args, **kwargs):
if name == "pynvml":
raise ImportError("pynvml is not installed in this venv")
return real_import(name, *args, **kwargs)
monkeypatch.setattr(builtins, "__import__", no_pynvml)
out = engine.gpu_attribution_for_tree()
assert out["per_process_gpu_attribution"] is None
assert engine._host_kind() in out["per_process_gpu_attribution_reason"]
assert "WSL2" not in out["per_process_gpu_attribution_reason"] or engine._host_kind() == "wsl2"
def _fake_pynvml(pids):
m = types.ModuleType("pynvml")
m.nvmlInit = lambda: None
m.nvmlShutdown = lambda: None
m.nvmlDeviceGetHandleByIndex = lambda i: object()
m.nvmlDeviceGetComputeRunningProcesses = lambda h: [
types.SimpleNamespace(pid=p, usedGpuMemory=1234) for p in pids
]
return m
def test_attribution_is_data_when_nvml_lists_our_pid(monkeypatch):
import os
monkeypatch.setitem(sys.modules, "pynvml", _fake_pynvml([os.getpid(), 1]))
out = engine.gpu_attribution_for_tree()
assert out["per_process_gpu_attribution"] == [
{"pid": os.getpid(), "used_gpu_memory": 1234}
]
assert out["per_process_gpu_attribution_reason"] is None
def test_reason_states_the_measured_count_when_none_are_ours(monkeypatch):
monkeypatch.setitem(sys.modules, "pynvml", _fake_pynvml([1, 2]))
out = engine.gpu_attribution_for_tree()
assert out["per_process_gpu_attribution"] is None
reason = out["per_process_gpu_attribution_reason"]
assert reason.startswith("nvmlDeviceGetComputeRunningProcesses returned 2 process(es)")
host = engine._host_kind()
expected = {"wsl2": "WSL2", "windows": "WDDM", "linux": "no compute process"}[host]
assert expected in reason
+99
View File
@@ -0,0 +1,99 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
"""Identifying a checkpoint well enough to tell it from its siblings."""
import json
import pytest
from vllm_omni.edge.local.capabilities import FORMAT_DENSE, FORMAT_FP8, FORMAT_INT8
from vllm_omni.edge.local.manifest import build_manifest, runtime_versions
from .conftest import FP8_QUANT_CONFIG, INT8_QUANT_CONFIG, write_checkpoint
pytestmark = [pytest.mark.core_model, pytest.mark.cpu]
def test_quantization_format_is_read_from_the_config(tmp_path):
assert build_manifest(write_checkpoint(tmp_path / "d")).weight_format == FORMAT_DENSE
assert build_manifest(
write_checkpoint(tmp_path / "i", quantization=INT8_QUANT_CONFIG)
).weight_format == FORMAT_INT8
assert build_manifest(
write_checkpoint(tmp_path / "f", quantization=FP8_QUANT_CONFIG)
).weight_format == FORMAT_FP8
def test_compressed_tensors_int8_and_fp8_are_distinguished_by_format_not_method(tmp_path):
"""Both say ``compressed-tensors``; only ``format`` separates the one
Blackwell can execute from the one it cannot."""
int8 = build_manifest(write_checkpoint(tmp_path / "i", quantization=INT8_QUANT_CONFIG))
fp8 = build_manifest(write_checkpoint(tmp_path / "f", quantization=FP8_QUANT_CONFIG))
assert int8.quantization["quant_method"] == fp8.quantization["quant_method"]
assert int8.weight_format != fp8.weight_format
def test_two_quantizations_of_one_model_get_different_ids(tmp_path):
dense = build_manifest(write_checkpoint(tmp_path / "d"))
int8 = build_manifest(write_checkpoint(tmp_path / "i", quantization=INT8_QUANT_CONFIG))
assert dense.artifact_id != int8.artifact_id
def test_the_id_is_stable_across_reads(tmp_path):
path = write_checkpoint(tmp_path / "d")
assert build_manifest(path).artifact_id == build_manifest(path).artifact_id
def test_a_changed_tokenizer_changes_the_id(tmp_path):
"""The tokenizer decides what the model is asked, and moves independently
of the weights."""
path = write_checkpoint(tmp_path / "d")
before = build_manifest(path).artifact_id
(path / "chat_template.jinja").write_text("{{ different }}", encoding="utf-8")
assert build_manifest(path).artifact_id != before
def test_weights_are_not_hashed_unless_asked(tmp_path):
path = write_checkpoint(tmp_path / "d")
assert build_manifest(path).weight_sha256 is None
assert any("digest_weights" in n for n in build_manifest(path).notes)
assert build_manifest(path, digest_weights=True).weight_sha256 is not None
def test_weight_bytes_and_shards_are_recorded(tmp_path):
path = write_checkpoint(tmp_path / "d", weight_bytes=8192, shards=4)
manifest = build_manifest(path)
assert len(manifest.weight_files) == 4
assert manifest.weight_bytes == 8192
def test_a_directory_without_a_config_is_an_error(tmp_path):
(tmp_path / "empty").mkdir()
with pytest.raises(FileNotFoundError):
build_manifest(tmp_path / "empty")
def test_an_hf_snapshot_path_yields_its_revision(tmp_path):
root = tmp_path / "models--org--name" / "snapshots" / "deadbeef1234"
write_checkpoint(root)
assert build_manifest(root).revision == "deadbeef1234"
def test_a_local_checkpoint_reports_no_revision_rather_than_guessing(tmp_path):
assert build_manifest(write_checkpoint(tmp_path / "d")).revision is None
def test_the_runtime_records_both_the_wheel_and_the_checkout():
versions = runtime_versions()
assert versions.python
# The import path, not just the version string: an editable install and a
# site-packages copy report the same version and are different code.
assert versions.vllm_omni_file.endswith("__init__.py")
assert isinstance(versions.checkouts, dict)
def test_the_manifest_is_json_serialisable(tmp_path):
manifest = build_manifest(write_checkpoint(tmp_path / "d"))
back = json.loads(json.dumps(manifest.to_dict(), default=str))
assert back["artifact_id"] == manifest.artifact_id
assert back["architectures"] == ["Spark2_5ForCausalLM"]
+129
View File
@@ -0,0 +1,129 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
"""Reference consistency: does the Omni stage path change the model's answer?
The comparison logic is unit-tested here; the run that actually loads two
engines is at the bottom and skips without a checkpoint. It is separated from
``test_e2e_local_text`` because it cannot share that module's engine fixture --
it needs the reference engine loaded and released *before* the Omni one, and
two copies of a 7.7 GB checkpoint do not fit the budget this milestone is about.
"""
from __future__ import annotations
import os
from pathlib import Path
import pytest
from vllm_omni.edge.local.parity import compare_ids, summarize
from vllm_omni.edge.local.plan import plan_text_session
MAX_MODEL_LEN = 4096
# ------------------------------------------------------------------- unit
@pytest.mark.core_model
@pytest.mark.cpu
class TestCompare:
def test_identical_sequences_are_exact(self):
assert compare_ids([1, 2, 3], [1, 2, 3]) == (True, None, 3)
def test_a_divergence_reports_where(self):
assert compare_ids([1, 2, 3, 4], [1, 2, 9, 4]) == (False, 2, 2)
def test_a_short_engine_sequence_is_not_exact(self):
"""A truncation is a divergence at the end, not agreement."""
assert compare_ids([1, 2, 3], [1, 2]) == (False, 2, 2)
def test_a_long_engine_sequence_is_not_exact(self):
assert compare_ids([1, 2], [1, 2, 3]) == (False, 2, 2)
def test_divergence_at_the_first_token(self):
assert compare_ids([5, 6], [7, 6]) == (False, 0, 0)
def test_empty_sequences_agree_vacuously(self):
assert compare_ids([], []) == (True, None, 0)
def test_summary_counts_and_reports_the_worst_prefix(self):
from vllm_omni.edge.local.parity import PromptParity
rows = [
PromptParity("a", 4, 8, 8, True, None, 8),
PromptParity("b", 4, 8, 8, False, 5, 5),
PromptParity("c", 4, 8, 8, False, 1, 1),
]
stats = summarize(rows)
assert stats["exact"] == 1
assert stats["prompts"] == 3
assert stats["min_agreement_prefix"] == 1
assert stats["mean_agreement_prefix"] == 3.0
def test_an_all_exact_summary_has_no_divergence_stats(self):
from vllm_omni.edge.local.parity import PromptParity
stats = summarize([PromptParity("a", 4, 8, 8, True, None, 8)])
assert stats["exact_fraction"] == 1.0
assert stats["min_agreement_prefix"] is None
# -------------------------------------------------------------------- e2e
def _models_root() -> Path:
return Path(__file__).resolve().parents[3].parent / "models"
def _platform() -> str:
from vllm.platforms import current_platform
return str(getattr(current_platform, "device_type", "") or "")
def _find_model() -> str:
override = os.environ.get("VLLM_OMNI_LOCAL_TEST_MODEL")
if override:
return override
candidates = ("Spark-X2.5-4B",) if _platform() == "cuda" else ("Spark-X2.5-1.7B-int8",)
for name in candidates:
if (_models_root() / name / "config.json").is_file():
return str(_models_root() / name)
pytest.skip(f"no Spark checkpoint for platform {_platform()!r}")
@pytest.mark.local_model
@pytest.mark.asyncio(loop_scope="module")
async def test_the_omni_path_decodes_what_plain_vllm_decodes():
"""The hard acceptance condition: same checkpoint, same limits, same
greedy decode -- the only difference is the path through the Omni stage.
Four prompts rather than the full twelve: this loads two engines and the
point is to detect a systematic difference in the stage path, which four
prompts of different shapes (short chat, tool-formatted, long, plain) show
as well as twelve. The full set runs from the CLI's ``parity`` command.
"""
from vllm_omni.edge.local.cli import _engine_token_ids
from vllm_omni.edge.local.parity import reference_token_ids
from vllm_omni.edge.local.prompts import acceptance_prompts
model_dir = _find_model()
plan = plan_text_session(model_dir, max_model_len=MAX_MODEL_LEN, max_num_seqs=1)
if not plan.admitted:
pytest.skip(f"this host cannot run {model_dir}")
all_prompts = dict(acceptance_prompts())
prompts = [(n, all_prompts[n]) for n in ("chat_short", "chat_tools", "chat_long", "plain_0")]
max_tokens = 64
reference = reference_token_ids(
model_dir, prompts, engine_kwargs=plan.engine_kwargs, max_tokens=max_tokens
)
engine = await _engine_token_ids(plan, prompts, max_tokens)
mismatches = []
for name, _ in prompts:
ref = reference[name]["token_ids"]
eng = engine[name]["token_ids"]
assert len(ref) == max_tokens, f"{name}: reference produced {len(ref)}"
exact, first, prefix = compare_ids(ref, eng)
if not exact:
mismatches.append(f"{name}: diverged at {first}/{len(ref)} (prefix {prefix})")
assert not mismatches, "the Omni stage path changed the decode:\n" + "\n".join(mismatches)
+200
View File
@@ -0,0 +1,200 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
"""Admission: say yes with a budget, or no with a reason and a remedy."""
import pytest
from vllm_omni.edge.local.plan import (
GiB,
REFUSE_CAPACITY,
REFUSE_FORMAT,
REFUSE_NO_DEVICE,
plan_text_session,
)
from .conftest import FP8_QUANT_CONFIG, blackwell_laptop, cpu_only_box, write_checkpoint
pytestmark = [pytest.mark.core_model, pytest.mark.cpu]
def _plan(model_dir, profile=None, platform="cuda", **kw):
return plan_text_session(
str(model_dir),
profile=profile if profile is not None else blackwell_laptop(),
platform_device_type=platform,
**kw,
)
def _codes(plan):
return {r.code for r in plan.refusals}
# ------------------------------------------------------------------ the yes
def test_a_dense_checkpoint_is_admitted_to_the_gpu(dense_checkpoint):
plan = _plan(dense_checkpoint)
assert plan.admitted
assert plan.selected.device_id == "cuda:0"
assert plan.backend == "vllm:cuda"
def test_an_admitted_plan_prices_every_line_of_section_6_2(dense_checkpoint):
"""The budget is not 'the weights'. It is the sum the design specifies,
and each term has to be visible so a reviewer can argue with one."""
plan = _plan(dense_checkpoint)
purposes = {r.purpose for r in plan.reservations}
assert purposes == {
"weights", "kv_cache", "activations", "backend_workspace",
"load_transient", "external_reserve", "safety_margin",
}
assert all(r.pool == "vram" for r in plan.reservations)
assert all(r.evidence in {"D", "E"} for r in plan.reservations)
# The weights line is read off the files, not estimated.
weights = next(r for r in plan.reservations if r.purpose == "weights")
assert weights.evidence == "D"
assert weights.bytes == plan.manifest.weight_bytes
def test_graph_capture_is_charged_only_when_graphs_are_on(dense_checkpoint):
eager = _plan(dense_checkpoint, enforce_eager=True)
graphs = _plan(dense_checkpoint, enforce_eager=False)
assert "graph_capture" not in {r.purpose for r in eager.reservations}
assert "graph_capture" in {r.purpose for r in graphs.reservations}
assert graphs.peak_bytes > eager.peak_bytes
def test_the_peak_is_a_max_not_a_sum(dense_checkpoint):
"""The loader's transient is gone before the KV pool is sized, so adding
both would refuse plans that fit."""
plan = _plan(dense_checkpoint)
everything = sum(r.bytes for r in plan.reservations)
assert plan.peak_bytes <= everything
def test_kv_reservation_tracks_the_context(dense_checkpoint):
short = _plan(dense_checkpoint, max_model_len=1024)
long = _plan(dense_checkpoint, max_model_len=8192)
kv_short = next(r for r in short.reservations if r.purpose == "kv_cache").bytes
kv_long = next(r for r in long.reservations if r.purpose == "kv_cache").bytes
assert kv_long > kv_short
def test_sliding_layers_are_not_charged_full_length(dense_checkpoint):
"""21 of 28 layers hold a 512 window, not the whole context. Charging them
all at full length is the arithmetic the kv_budget module exists to fix."""
plan = _plan(dense_checkpoint, max_model_len=8192)
assert plan.kv_budget.sliding_layers == 21
assert plan.kv_budget.full_layers == 7
assert plan.kv_budget.bytes_total_hybrid < plan.kv_budget.bytes_total
# ------------------------------------------------------------------- the no
def test_int8_is_refused_on_blackwell_although_it_fits(int8_checkpoint):
"""4 MiB of weights against 24 GiB of VRAM: every capacity check passes and
the answer is still no."""
plan = _plan(int8_checkpoint)
assert not plan.admitted
assert REFUSE_FORMAT in _codes(plan)
refusal = next(r for r in plan.refusals if r.code == REFUSE_FORMAT)
assert refusal.device_id == "cuda:0"
assert "int8" in refusal.message
assert "omni-cpu" in refusal.remedy
def test_the_same_int8_checkpoint_is_admitted_on_the_cpu(int8_checkpoint):
"""The remedy the refusal names has to actually be a plan."""
plan = _plan(int8_checkpoint, profile=cpu_only_box(), platform="cpu")
assert plan.admitted
assert plan.selected.device_id == "cpu"
assert plan.backend == "vllm:cpu"
def test_fp8_is_admitted_where_int8_is_not(tmp_path):
fp8 = write_checkpoint(tmp_path / "fp8", quantization=FP8_QUANT_CONFIG)
assert _plan(fp8).admitted
def test_a_checkpoint_too_large_for_the_pool_is_refused_with_a_number(tmp_path):
huge = write_checkpoint(tmp_path / "huge", weight_bytes=40 * GiB, shards=8)
plan = _plan(huge)
assert not plan.admitted
assert REFUSE_CAPACITY in _codes(plan)
refusal = next(r for r in plan.refusals if r.code == REFUSE_CAPACITY)
assert "GiB" in refusal.message
def test_a_capacity_refusal_never_silently_shortens_the_context(tmp_path):
"""Trimming max_model_len is offered as a remedy the operator applies, not
something the planner does on its behalf."""
# Sized so the overrun is smaller than the KV cache it asked for: that is
# the case where a shorter context would in fact fit, which is exactly when
# an engine that "helpfully" truncates would do damage.
big = write_checkpoint(tmp_path / "big", weight_bytes=16 * GiB, shards=8)
plan = _plan(big, max_model_len=131072)
assert not plan.admitted
refusal = next(r for r in plan.refusals if r.code == REFUSE_CAPACITY)
assert "max-model-len" in refusal.remedy
assert "forbids" in refusal.remedy
# And the plan still reports the context that was asked for, not a
# quietly reduced one.
assert plan.request_limits["max_model_len"] == 131072
def test_masking_the_gpu_leaves_nothing_runnable_in_a_cuda_process(dense_checkpoint):
"""The capability-masked startup of the acceptance run: a refusal here is
the correct outcome, not a failure."""
plan = _plan(dense_checkpoint, mask=frozenset({"gpu_discrete"}))
assert not plan.admitted
assert REFUSE_NO_DEVICE in _codes(plan)
assert any("mask" in r.message for r in plan.refusals)
def test_every_unusable_device_is_explained(dense_checkpoint):
plan = _plan(dense_checkpoint)
explained = {r.device_id for r in plan.refusals}
assert {"cpu", "npu:amd", "gpu_integrated:amd"} <= explained
assert all(r.message and r.remedy for r in plan.refusals)
# ------------------------------------------------------------ engine kwargs
def test_the_memory_fraction_is_derived_not_defaulted(dense_checkpoint):
"""vLLM reads this field as host RAM on the CPU backend, so leaving it at
its default there asks for 92% of the machine. It is always derived."""
for platform, profile in (("cuda", blackwell_laptop()), ("cpu", cpu_only_box())):
plan = _plan(dense_checkpoint, profile=profile, platform=platform)
assert plan.admitted
fraction = plan.engine_kwargs["gpu_memory_utilization"]
assert 0 < fraction <= 0.95
assert fraction >= plan.peak_bytes / plan.selected.memory_bytes * 0.5
def test_the_kv_pool_is_absolute_not_leftover(dense_checkpoint):
plan = _plan(dense_checkpoint)
assert plan.engine_kwargs["kv_cache_memory_bytes"] == plan.kv_budget.bytes_total
def test_request_limits_reach_the_backend(dense_checkpoint):
plan = _plan(dense_checkpoint, max_model_len=2048, max_num_seqs=2)
assert plan.engine_kwargs["max_model_len"] == 2048
assert plan.engine_kwargs["max_num_seqs"] == 2
assert plan.engine_kwargs["enforce_eager"] is True
# ---------------------------------------------------------------- the stage
def test_the_plan_declares_exactly_one_text_stage(dense_checkpoint):
plan = _plan(dense_checkpoint)
assert plan.stage["stage_id"] == 0
assert plan.stage["execution_type"] == "LLM_AR"
assert plan.stage["final_output_type"] == "text"
assert plan.stage["input_sources"] == []
def test_the_record_round_trips_to_json(dense_checkpoint):
import json
plan = _plan(dense_checkpoint)
text = json.dumps(plan.to_dict(), default=str)
back = json.loads(text)
assert back["admitted"]
assert back["selected_device"]["device_id"] == "cuda:0"
assert back["manifest"]["artifact_id"] == plan.manifest.artifact_id
+156
View File
@@ -0,0 +1,156 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
"""The event stream: backpressure that blocks, and an epoch that fences."""
import asyncio
import pytest
from vllm_omni.edge.local.session import (
STATE_LAYOUT_VERSION,
BoundedEventStream,
ChunkEvent,
StateHandle,
StreamClosed,
)
pytestmark = [pytest.mark.core_model, pytest.mark.cpu]
def _event(seq: int, *, epoch: int = 0, text: str = "x", kind: str = "token") -> ChunkEvent:
return ChunkEvent(
request_id="r", stage_id=0, seq=seq, epoch=epoch, kind=kind,
payload={"text": text}, started_unix=0.0, emitted_unix=0.0,
)
# -------------------------------------------------------------- state handle
def test_a_handle_carries_the_artifact_it_was_made_for():
handle = StateHandle(session_id="s", backend="vllm:cuda", artifact_id="abc")
assert handle.layout_version == STATE_LAYOUT_VERSION
assert handle.accepts(handle)
def test_state_from_another_checkpoint_is_not_accepted():
"""Same shapes from a different quantization are not the same state."""
a = StateHandle(session_id="s", backend="vllm:cuda", artifact_id="abc")
b = StateHandle(session_id="s", backend="vllm:cuda", artifact_id="def")
assert not a.accepts(b)
def test_state_from_a_retired_epoch_is_not_accepted():
handle = StateHandle(session_id="s", backend="vllm:cuda", artifact_id="abc")
assert not handle.next_epoch().accepts(handle)
def test_state_is_never_migratable_in_m0():
handle = StateHandle(session_id="s", backend="vllm:cuda", artifact_id="abc")
assert handle.migratable is False
assert handle.replayable is True
# ---------------------------------------------------------------- ordering
async def test_events_arrive_in_order():
stream = BoundedEventStream()
for i in range(5):
await stream.put(_event(i))
await stream.close()
assert [e.seq async for e in stream] == [0, 1, 2, 3, 4]
async def test_closing_ends_the_iteration():
stream = BoundedEventStream()
await stream.put(_event(0))
await stream.close()
seen = [e async for e in stream]
assert len(seen) == 1
async def test_producing_after_close_raises():
stream = BoundedEventStream()
await stream.close()
with pytest.raises(StreamClosed):
await stream.put(_event(0))
# ------------------------------------------------------------ backpressure
async def test_a_full_queue_blocks_the_producer():
"""The bound has to actually stop the producer. A queue that grows instead
is how a slow consumer turns into an OOM."""
stream = BoundedEventStream(max_chunks=2, max_bytes=1 << 20)
await stream.put(_event(0))
await stream.put(_event(1))
blocked = asyncio.create_task(stream.put(_event(2)))
await asyncio.sleep(0.05)
assert not blocked.done()
await stream.get() # consumer drains one; credit returns
await asyncio.wait_for(blocked, timeout=1.0)
assert stream.high_water_chunks == 2
async def test_the_byte_bound_also_blocks():
stream = BoundedEventStream(max_chunks=100, max_bytes=64)
await stream.put(_event(0, text="a" * 40))
blocked = asyncio.create_task(stream.put(_event(1, text="b" * 40)))
await asyncio.sleep(0.05)
assert not blocked.done()
await stream.get()
await asyncio.wait_for(blocked, timeout=1.0)
async def test_an_oversized_event_still_gets_through_on_an_empty_queue():
"""Otherwise one chunk larger than the whole bound deadlocks forever."""
stream = BoundedEventStream(max_chunks=4, max_bytes=8)
await asyncio.wait_for(stream.put(_event(0, text="x" * 400)), timeout=1.0)
assert (await stream.get()).seq == 0
async def test_closing_wakes_a_blocked_producer():
stream = BoundedEventStream(max_chunks=1, max_bytes=1 << 20)
await stream.put(_event(0))
blocked = asyncio.create_task(stream.put(_event(1)))
await asyncio.sleep(0.05)
await stream.close()
with pytest.raises(StreamClosed):
await asyncio.wait_for(blocked, timeout=1.0)
# ------------------------------------------------------------------- epochs
async def test_a_retired_epoch_cannot_be_produced_into():
stream = BoundedEventStream()
stream.retire_epoch(0)
await stream.put(_event(0, epoch=0))
await stream.close()
assert [e async for e in stream] == []
assert stream.dropped_stale == 1
async def test_events_already_queued_from_a_retired_epoch_are_not_delivered():
"""The real cancellation race: the backend had tokens in flight when the
cancel landed, and they must not reach the consumer."""
stream = BoundedEventStream()
for i in range(3):
await stream.put(_event(i, epoch=0))
stream.retire_epoch(0)
await stream.put(_event(0, epoch=1, text="new"))
await stream.close()
delivered = [e async for e in stream]
assert [e.epoch for e in delivered] == [1]
assert stream.dropped_stale == 3
async def test_retiring_is_monotonic():
stream = BoundedEventStream()
stream.retire_epoch(3)
stream.retire_epoch(0)
assert stream.epoch == 4
async def test_stats_report_the_bounds_and_what_was_dropped():
stream = BoundedEventStream(max_chunks=8, max_bytes=256)
await stream.put(_event(0))
stats = stream.stats()
assert stats["max_chunks"] == 8
assert stats["max_bytes"] == 256
assert stats["high_water_chunks"] == 1
assert stats["dropped_stale"] == 0
+138
View File
@@ -115,3 +115,141 @@ def test_live_probe_runs_on_this_host():
p = hp.probe(use_torch=False)
assert p.n_logical >= 1 and p.ram_total_bytes > 0
assert hp.hardware_class(p) in hp.HW_CLASSES
# --------------------------------------------------------- accelerators
def _ryzen_ai_root(tmp_path: Path, *, wsl: bool, driver: bool = True) -> Path:
"""A Ryzen AI laptop: XDNA2 NPU, Radeon iGPU, and one discrete card.
Under WSL none of it has a device node; on native Linux the NPU shows up
at ``/dev/accel/accel0`` and the GPUs at ``/dev/dri/renderD*``.
"""
root = _snapshot(tmp_path, X86_CPUINFO, cpus={0: (5100, 0), 1: (5100, 1)})
(root / "proc" / "version").write_text(
"Linux version 6.18.33.2-microsoft-standard-WSL2" if wsl
else "Linux version 6.18.0-generic (gcc 14)"
)
npu = root / "sys" / "bus" / "pci" / "devices" / "0000:c5:00.1"
npu.mkdir(parents=True)
(npu / "vendor").write_text("0x1022\n")
(npu / "device").write_text("0x17f0\n")
if wsl:
return root
if driver:
(npu / "driver").mkdir()
node = root / "sys" / "class" / "accel" / "accel0" / "device"
node.mkdir(parents=True)
(node / "vendor").write_text("0x1022\n")
(node / "device").write_text("0x17f0\n")
(node / "driver").mkdir()
(root / "dev" / "accel").mkdir(parents=True)
(root / "dev" / "accel" / "accel0").write_text("")
(root / "dev" / "dri").mkdir(parents=True)
for name, vendor in (("renderD128", "0x1002"), ("renderD129", "0x10de")):
(root / "dev" / "dri" / name).write_text("")
d = root / "sys" / "class" / "drm" / name / "device"
d.mkdir(parents=True)
(d / "vendor").write_text(vendor + "\n")
(d / "device").write_text("0x150e\n")
return root
def test_native_linux_finds_the_npu_and_both_gpus(tmp_path):
p = hp.probe(_ryzen_ai_root(tmp_path, wsl=False), use_torch=False)
assert p.host_os == hp.HOST_OS_LINUX
(npu,) = p.npus
assert npu["usable"] and npu["name"].startswith("AMD XDNA2")
assert [a["kind"] for a in p.accelerators].count(hp.ACCEL_GPU_INTEGRATED) == 1
assert p.accelerators_of(hp.ACCEL_GPU_DISCRETE, usable=True)
assert p.unusable_accelerators == []
def test_an_npu_with_no_driver_is_reported_present_and_unusable(tmp_path):
""""No /dev/accel node" and "no such hardware" need different answers."""
p = hp.probe(_ryzen_ai_root(tmp_path, wsl=False, driver=False), use_torch=False)
(npu,) = p.npus
assert npu["usable"] is False
assert "amdxdna" in npu["reason"]
def test_wsl_is_detected_and_sees_none_of_the_host_devices(tmp_path):
"""The iGPU and the NPU are in the machine and unreachable from Linux;
the probe must not report either as absent or as available."""
p = hp.probe(_ryzen_ai_root(tmp_path, wsl=True), use_torch=False, probe_host=False)
assert p.host_os == hp.HOST_OS_WSL2
# The PCI sweep still finds the NPU; there is simply no way to open it.
(npu,) = p.npus
assert npu["usable"] is False
assert p.accelerators_of(hp.ACCEL_GPU_INTEGRATED, usable=True) == []
def test_a_snapshot_root_never_shells_out_to_the_host(tmp_path):
"""probe_host defaults on, but a captured snapshot must stay hermetic."""
p = hp.probe(_ryzen_ai_root(tmp_path, wsl=True), use_torch=False, probe_host=True)
assert all(a["source"] != "wsl-interop" for a in p.accelerators)
def test_accelerators_survive_the_json_roundtrip(tmp_path):
p = hp.probe(_ryzen_ai_root(tmp_path, wsl=False), use_torch=False)
back = hp.HardwareProfile.from_json(p.to_json())
assert back.accelerators == p.accelerators
assert back.host_os == p.host_os
def test_describe_accelerators_says_why_each_one_is_out_of_reach(tmp_path):
p = hp.probe(_ryzen_ai_root(tmp_path, wsl=True), use_torch=False, probe_host=False)
text = hp.describe_accelerators(p)
assert "not here" in text and "amdxdna" in text
# ------------------------------------------------------- reachability routes
def test_the_npu_reason_names_the_recipe_not_just_the_symptom():
"""The iGPU and the NPU are both off-limits to a default WSL process, but
for different reasons with different fixes. A blanket "unreachable" loses
the only part a reader can act on -- and for the NPU the actionable part is
a three-part recipe, each part of which fails silently on its own."""
assert "MCDM" in hp._WSL_NPU_ROUTE # why WSL cannot see it
assert "onnxruntime_vitisai_ep" in hp._WSL_NPU_ROUTE # which of the two EPs
assert "DLL search path" in hp._WSL_NPU_ROUTE # how to make it load
assert "A16W8" in hp._WSL_NPU_ROUTE # what it will accept
assert "torch-directml" in hp._WSL_IGPU_ROUTE # the iGPU's other fix
def test_the_npu_recipe_module_states_the_three_preconditions():
"""Each of the three can fail on its own and the symptom is identical:
a session that runs correctly with every node on the CPU."""
from vllm_omni.edge import npu_ryzenai as npu
assert npu.EP_GENERAL == "onnxruntime_vitisai_ep.dll"
assert npu.EP_LIGHT != npu.EP_GENERAL
assert npu.PARTITION_TARGET == "AMD_AIE2P_4x8_CMC_Overlay"
kw = npu.quantization_kwargs()
# A16W8: 16-bit activations, 8-bit weights. A8W8 is silently rejected.
assert "16" in str(kw["activation_type"])
assert "8" in str(kw["weight_type"]) and "16" not in str(kw["weight_type"])
def test_the_igpu_is_usable_exactly_when_directml_is_importable(monkeypatch):
"""torch-directml pins torch==2.4.1, so it never shares the engine's venv.
``usable`` must answer for *this* process, not for the machine."""
calls = {"n": 0}
def fake_run(*a, **k):
calls["n"] += 1
class R: stdout = "AMD Radeon(TM) 890M Graphics\n"
return R()
import subprocess
monkeypatch.setattr(subprocess, "run", fake_run)
monkeypatch.setattr(hp, "directml_available", lambda: False)
(igpu,) = [a for a in hp.wsl_host_accelerators() if a["kind"] == hp.ACCEL_GPU_INTEGRATED]
assert igpu["usable"] is False and igpu["route"] == "directml"
monkeypatch.setattr(hp, "directml_available", lambda: True)
(igpu,) = [a for a in hp.wsl_host_accelerators() if a["kind"] == hp.ACCEL_GPU_INTEGRATED]
assert igpu["usable"] is True
def test_directml_available_is_false_without_the_package(monkeypatch):
monkeypatch.setitem(__import__("sys").modules, "torch_directml", None)
assert hp.directml_available() is False
+97
View File
@@ -105,3 +105,100 @@ def test_dtype_bytes_covers_the_kv_dtypes_vllm_accepts():
def test_summary_names_the_shape_it_priced():
s = kv_budget_for(_spark(), max_model_len=32768).summary()
assert "flat" in s and "21 sliding@512" in s and "MiB" in s
def _qwen3_8(**kw) -> _Cfg:
"""Qwen3.8-27B: 64 layers, 3 linear (gated DeltaNet) to 1 full, 4 KV
heads x 256. The linear layers hold a recurrent state and no KV."""
layer_types = ["linear_attention"] * 3 + ["full_attention"]
base = dict(
num_hidden_layers=64, num_attention_heads=24, num_key_value_heads=4,
head_dim=256, hidden_size=5120, layer_types=layer_types * 16,
linear_num_key_heads=16, linear_num_value_heads=48,
linear_key_head_dim=128, linear_value_head_dim=128,
linear_conv_kernel_dim=4, mamba_ssm_dtype="float32",
)
base.update(kw)
return _Cfg(**base)
class _Outer:
"""A multimodal config: the decoder geometry lives one level down."""
def __init__(self, text):
self.text_config = text
self.model_type = "qwen3_5"
def get_text_config(self):
return self.text_config
def test_linear_attention_layers_are_charged_no_kv_at_all():
"""Not "a shorter cache" -- none. A flat 64-layer price is 4x the truth."""
b = kv_budget_for(_qwen3_8(), max_model_len=8192)
assert (b.linear_layers, b.full_layers, b.sliding_layers) == (48, 16, 0)
# 16 full layers x 4 KV heads x 256 x 2 (K and V) x 2 bytes = 64 KiB.
assert b.bytes_per_token_flat == 16 * 4 * 256 * 2 * 2 == 64 * 1024
assert b.token_layers_flat == 16 * 8192
def test_the_recurrent_state_is_sized_from_vllms_own_shapes():
"""conv (kernel-1, 2*k_heads*k_dim + v_heads*v_dim); temporal
(v_heads, v_dim, k_dim) in mamba_ssm_dtype."""
b = kv_budget_for(_qwen3_8(), max_model_len=8192)
conv_dim = 128 * 16 * 2 + 128 * 48
per_layer = (4 - 1) * conv_dim * 2 + 48 * 128 * 128 * 4
assert b.state_bytes_per_seq == 48 * per_layer
assert b.state_bytes_per_seq / 2**20 == pytest.approx(147.0, abs=0.5)
assert b.state_bytes_total == b.state_bytes_per_seq # max_num_seqs=1
def test_the_state_is_inside_the_budget_and_scales_with_sequences():
"""It comes out of the same pool as the KV cache, so a budget that
reports only the cache is short before the first token."""
one = kv_budget_for(_qwen3_8(), max_model_len=8192, max_num_seqs=1)
two = kv_budget_for(_qwen3_8(), max_model_len=8192, max_num_seqs=2)
assert two.state_bytes_total == 2 * one.state_bytes_total
assert one.bytes_total > one.state_bytes_total
kv_only = int(one.token_layers_flat * one.bytes_per_token_flat / 16 * 1.25)
assert one.bytes_total == kv_only + one.state_bytes_total
def test_the_state_dominates_a_short_context():
"""147 MiB of state against 64 KiB/token: the cache only outgrows it past
~2350 tokens, so over an edge deployment's range the constant is the
bigger half. The crossover is on raw bytes -- ``headroom`` is a safety
factor on the cache, not a cost the state has to beat."""
assert kv_budget_for(
_qwen3_8(), max_model_len=2048
).state_crossover_tokens == pytest.approx(2352, abs=8)
short = kv_budget_for(_qwen3_8(), max_model_len=1024)
assert short.state_bytes_total > short.bytes_total - short.state_bytes_total
long = kv_budget_for(_qwen3_8(), max_model_len=32768)
assert long.state_bytes_total < long.bytes_total - long.state_bytes_total
def test_a_model_without_linear_layers_reports_no_state():
b = kv_budget_for(_spark(), max_model_len=2048)
assert b.linear_layers == 0
assert b.state_bytes_per_seq == 0
assert b.state_crossover_tokens == float("inf")
def test_a_multimodal_config_is_resolved_to_its_text_config():
"""Qwen3_5Config has no num_hidden_layers; this used to raise."""
nested = kv_budget_for(_Outer(_qwen3_8()), max_model_len=8192)
direct = kv_budget_for(_qwen3_8(), max_model_len=8192)
assert nested == direct
def test_linear_layers_without_their_geometry_raise_rather_than_guess():
cfg = _qwen3_8()
del cfg.linear_num_value_heads
with pytest.raises(ValueError, match="linear_num_value_heads"):
kv_budget_for(cfg, max_model_len=8192)
def test_summary_names_the_state_it_priced():
s = kv_budget_for(_qwen3_8(), max_model_len=8192).summary()
assert "recurrent state for 48 linear layers" in s
+214
View File
@@ -0,0 +1,214 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
"""Placing a checkpoint that does not fit in the VRAM."""
import json
import struct
import pytest
from vllm_omni.edge.placement import (
GiB,
ParamGroup,
checkpoint_param_groups,
group_key,
is_cold,
plan_placement,
)
pytestmark = [pytest.mark.core_model, pytest.mark.cpu]
LINK = 13.9e9 # measured pinned H2D on the reference laptop, PCIe 4.0 x8
VRAM = 472e9 # measured VRAM bandwidth on the same machine
def _plan(groups, avail_gib, **kw):
return plan_placement(
groups, device_bytes_available=int(avail_gib * GiB),
link_bytes_per_s=LINK, vram_bytes_per_s=VRAM, **kw)
# ------------------------------------------------------------ classification
def test_embed_tokens_is_cold_and_lm_head_is_not():
"""Same shape, same dtype, opposite decision: the embedding is a gather
and the head is a GEMM over the whole table."""
assert is_cold("model.language_model.embed_tokens.weight")
assert not is_cold("lm_head.weight")
def test_cold_matching_is_by_segment_not_substring():
assert is_cold("model.visual.blocks.0.attn.qkv.weight")
assert not is_cold("model.visualiser.weight")
def test_a_decoder_layer_is_never_folded_into_one_group():
"""A 3-segment prefix makes all 64 layers a single 24 GB group, and a
planner that moves groups whole then has no choice between none and all."""
assert group_key("model.language_model.layers.17.mlp.down_proj.weight") == (
"model.language_model.layers.17")
assert group_key("model.visual.blocks.3.attn.qkv.weight").startswith("model.visual")
# ------------------------------------------------------------------ planning
def test_a_checkpoint_that_fits_is_left_alone():
groups = [ParamGroup("model.layers.0", 8 * GiB, False)]
p = _plan(groups, 20)
assert p.strategy == "resident"
assert p.host_bytes == 0 and p.est_link_s_per_token == 0.0
assert p.engine_kwargs == {}
def test_the_deficit_comes_out_of_the_cold_set_first():
"""4 GiB over, and there is 6 GiB of cold weight to spend: nothing that a
decode step reads should end up on the host."""
groups = [
ParamGroup("model.layers.0", 18 * GiB, False),
ParamGroup("model.embed_tokens", 6 * GiB, True),
]
p = _plan(groups, 20)
assert p.strategy == "cold_offload"
assert p.host_bytes == 6 * GiB
assert p.host_read_per_token == 0
assert p.est_link_s_per_token == 0.0
def test_an_offloaded_embedding_still_pays_one_row_per_token():
groups = [
ParamGroup("model.layers.0", 18 * GiB, False),
ParamGroup("model.embed_tokens", 6 * GiB, True),
]
p = _plan(groups, 20, embedding_row_bytes=5120 * 2)
assert p.host_read_per_token == 5120 * 2
# 10 KiB over a 13.9 GB/s link is well under a microsecond.
assert p.est_link_s_per_token < 1e-6
def test_hot_weight_is_only_spent_once_the_cold_set_runs_out():
groups = [
ParamGroup("model.embed_tokens", 2 * GiB, True),
*[ParamGroup(f"model.layers.{i}", 1 * GiB, False) for i in range(20)],
]
p = _plan(groups, 16)
assert p.strategy == "hot_offload"
# 6 GiB over; 2 GiB is free, so exactly 4 layers should cross.
assert p.host_read_per_token == 4 * GiB
assert p.host_bytes == 6 * GiB
def test_the_estimate_prices_host_bytes_at_the_link_and_the_rest_at_vram():
groups = [
ParamGroup("model.embed_tokens", 2 * GiB, True),
*[ParamGroup(f"model.layers.{i}", 1 * GiB, False) for i in range(20)],
]
p = _plan(groups, 16)
assert p.est_link_s_per_token == pytest.approx(4 * GiB / LINK)
assert p.est_vram_s_per_token == pytest.approx(16 * GiB / VRAM)
# The link is 34x slower, so 4 GiB on the host outweighs 16 GiB resident.
assert p.est_link_s_per_token > 8 * p.est_vram_s_per_token
def test_a_checkpoint_too_big_for_host_and_device_says_so():
groups = [ParamGroup("model.layers.0", 40 * GiB, False)]
p = _plan(groups, 8)
# Everything hot can still move to the host, so this one is feasible but
# miserable; infeasible needs the groups themselves to run out.
assert p.strategy == "hot_offload"
assert p.deficit_bytes == 32 * GiB
def test_engine_kwargs_name_only_segments_vllm_can_match():
groups = [
ParamGroup("model.embed_tokens", 6 * GiB, True),
ParamGroup("model.layers.0", 18 * GiB, False),
]
kw = _plan(groups, 20).engine_kwargs
assert kw["cpu_offload_params"] == ["embed_tokens"]
assert kw["cpu_offload_gb"] >= 6.0
assert "offload_group_size" not in kw # nothing hot was offloaded
# --------------------------------------------------------------- checkpoints
def _write_shard(path, tensors):
"""A minimal safetensors file: 8-byte header length, JSON header, data."""
header, off = {}, 0
for name, nbytes in tensors:
header[name] = {"dtype": "BF16", "shape": [nbytes // 2],
"data_offsets": [off, off + nbytes]}
off += nbytes
blob = json.dumps(header).encode()
path.write_bytes(struct.pack("<Q", len(blob)) + blob + b"\0" * off)
def test_param_groups_are_read_from_headers_without_loading_weights(tmp_path):
_write_shard(tmp_path / "a.safetensors", [
("model.language_model.embed_tokens.weight", 4096),
("lm_head.weight", 4096),
("model.language_model.layers.0.mlp.down_proj.weight", 2048),
("model.language_model.layers.1.mlp.down_proj.weight", 2048),
])
groups = {g.name: g for g in checkpoint_param_groups(tmp_path)}
assert groups["model.language_model.embed_tokens"].cold
assert not groups["lm_head.weight"].cold
assert set(groups) >= {"model.language_model.layers.0",
"model.language_model.layers.1"}
assert groups["model.language_model.layers.0"].bytes == 2048
def test_a_group_is_cold_only_if_every_tensor_in_it_is(tmp_path):
_write_shard(tmp_path / "a.safetensors", [
("model.visual.blocks.0.attn.qkv.weight", 1024),
("model.visual.blocks.0.lm_head.weight", 1024), # contrived, but hot
])
(group,) = [g for g in checkpoint_param_groups(tmp_path)
if g.name.startswith("model.visual")]
assert not group.cold
def test_a_directory_with_no_shards_raises(tmp_path):
with pytest.raises(FileNotFoundError, match="safetensors"):
checkpoint_param_groups(tmp_path)
# ------------------------------------------- the cost model, against hardware
# Qwen3.8-27B-FP8, 4096-token context, batch 1, greedy, eager, idle machine.
# Four points from benchmarks/edge_harness; see docs/edge/laptop-heterogeneous.md.
MEASURED_S_PER_TOKEN = {10: 0.952, 12: 1.124, 14: 1.316, 16: 1.515}
QWEN38_FP8_GB = 30.87
def test_the_estimate_reproduces_the_measured_offload_curve():
"""The whole design rests on `resident/472 + offloaded/10.6`. It is worth
one test that the arithmetic matches the hardware it claims to describe.
It runs slightly *pessimistic* at every point, which is the right
direction for a number used to decide whether a build will fit.
"""
# 0.25 GB chunks, so the planner offloads close to exactly the target
# rather than having to take one oversized group whole -- which is also
# what the real checkpoint looks like at 0.38 GB per decoder layer.
CHUNK = 0.25
n = round(QWEN38_FP8_GB / CHUNK)
for offloaded_gb, measured in MEASURED_S_PER_TOKEN.items():
groups = [ParamGroup(f"layers.{i}", int(CHUNK * 1e9), False) for i in range(n)]
p = plan_placement(
groups,
device_bytes_available=int((QWEN38_FP8_GB - offloaded_gb) * 1e9),
link_bytes_per_s=10.6e9, vram_bytes_per_s=472e9,
)
modelled = p.est_link_s_per_token + p.est_vram_s_per_token
assert modelled == pytest.approx(measured, rel=0.05), (
f"{offloaded_gb} GB: modelled {modelled:.3f}s vs measured {measured:.3f}s")
assert modelled >= measured, "the estimate must not flatter the build"
def test_the_link_term_dominates_at_every_measured_point():
"""At the tightest fit the 10 GB on the host is ~94% of the step. If this
ever stops being true the advice in the design document changes."""
groups = [
ParamGroup("resident", int(20.87e9), False),
ParamGroup("onhost", int(10e9), False),
]
p = plan_placement(groups, device_bytes_available=int(20.87e9),
link_bytes_per_s=10.6e9, vram_bytes_per_s=472e9)
share = p.est_link_s_per_token / (p.est_link_s_per_token + p.est_vram_s_per_token)
assert share > 0.9
+20
View File
@@ -105,6 +105,26 @@ def test_masked_cache_slots_do_not_change_the_result():
assert torch.allclose(first, module(*args)[0], atol=1e-5)
def test_llama_style_config_skips_qk_norm():
"""MiniCPM-o's TTS head is a Llama decoder: no per-head q/k RMSNorm, so those params must not be applied."""
cfg = qx.DecodeStepConfig(**{**{f.name: getattr(CFG, f.name) for f in CFG.__dataclass_fields__.values()}, "qk_norm": False})
module = qx.DecodeStep(cfg).eval()
for p in module.parameters():
torch.nn.init.normal_(p, std=0.15)
args = qx.example_inputs(cfg, L)
before = module(*args)[0].clone()
with torch.no_grad(): # q_norm/k_norm must be dead weights when qk_norm is off
module.layers[0].q_norm.mul_(3.0)
module.layers[0].k_norm.mul_(0.1)
assert torch.equal(before, module(*args)[0])
def test_minicpmo_config_maps_the_tts_head():
cfg = qx.config_from_minicpmo({"tts_config": {"num_hidden_layers": 20, "hidden_size": 768, "num_attention_heads": 12,
"num_key_value_heads": 12, "intermediate_size": 3072, "num_audio_tokens": 6562}})
assert cfg.qk_norm is False and cfg.head_dim == 64 and cfg.vocab_size == 6562 and cfg.group_size == 1
def test_placement_table_prefers_npu_for_the_step_and_gpu_for_the_vocoder():
p = qx.PLACEMENT_MS_PER_FRAME
assert p["talker_step"]["npu"] < p["talker_step"]["gpu"]
@@ -243,3 +243,84 @@ def test_rope_table_is_capped_to_the_servable_context(monkeypatch):
if os.environ.get("VLLM_OMNI_SPARK_ROPE_FULL", "0") == "0":
max_position = min(max_position, 2048)
assert max_position == 1048576, "the escape hatch must restore the full table"
# ------------------------------------------------------- published sizes
# Spark-X2.5 ships at two sizes and the vLLM implementation is meant to be
# size-generic. It is, but only one of them had ever been run: the constants
# below are the published configs, so a change that quietly assumes 1.7B's
# 8 query heads or 28 layers fails here instead of on a checkpoint.
PUBLISHED = {
"XHToken/Spark-X2.5-1.7B": dict(
hidden_size=2048, intermediate_size=6656, num_hidden_layers=28,
num_attention_heads=8, num_key_value_heads=2,
),
"XHToken/Spark-X2.5-4B": dict(
hidden_size=2560, intermediate_size=10240, num_hidden_layers=36,
num_attention_heads=16, num_key_value_heads=4,
),
}
_COMMON = dict(
head_dim=256, vocab_size=131072, sliding_window=512, hidden_act="gelu",
headwise_attn_output_gate=True, tie_word_embeddings=True,
max_position_embeddings=1048576,
rope_parameters={
"full_attention": {"rope_theta": 5000000, "partial_rotary_factor": 0.25},
"sliding_attention": {"rope_theta": 10000, "partial_rotary_factor": 1.0},
},
)
def _published(name: str) -> Spark2_5Config:
kw = dict(_COMMON, **PUBLISHED[name])
n = kw["num_hidden_layers"]
kw["layer_types"] = (["sliding_attention"] * 3 + ["full_attention"]) * (n // 4)
return Spark2_5Config(**kw)
@pytest.mark.core_model
@pytest.mark.cpu
@pytest.mark.parametrize("name", sorted(PUBLISHED))
def test_published_configs_validate_and_keep_the_3_to_1_hybrid(name):
config = _published(name)
assert len(config.layer_types) == config.num_hidden_layers
assert config.layer_types.count("full_attention") == config.num_hidden_layers // 4
# Both sizes keep head_dim 256 and widen by head count, not by head width.
assert config.head_dim == 256
assert config.num_attention_heads % config.num_key_value_heads == 0
@pytest.mark.core_model
@pytest.mark.cpu
@pytest.mark.parametrize("name", sorted(PUBLISHED))
def test_split_fused_qkv_holds_at_both_published_head_counts(name):
"""4B is 16 q heads to 4 KV heads where 1.7B is 8 to 2. The split is by
dimension, not by a ratio, so getting one right does not imply the other."""
config = _published(name)
q_dim = config.num_attention_heads * config.head_dim
kv_dim = config.num_key_value_heads * config.head_dim
fused = torch.cat([
torch.full((q_dim, 8), 1.0),
torch.full((kv_dim, 8), 2.0),
torch.full((kv_dim, 8), 3.0),
], dim=0)
out = dict(_split_fused_qkv(
[("model.layers.0.self_attn.q_k_v_proj.weight", fused)], config))
assert out["model.layers.0.self_attn.q_proj.weight"].shape[0] == q_dim
assert out["model.layers.0.self_attn.k_proj.weight"].shape[0] == kv_dim
assert torch.all(out["model.layers.0.self_attn.q_proj.weight"] == 1.0)
assert torch.all(out["model.layers.0.self_attn.v_proj.weight"] == 3.0)
@pytest.mark.core_model
@pytest.mark.cpu
def test_4b_is_priced_as_a_hybrid_not_as_36_full_layers():
"""The KV budget reads the same config the model does; 4B is 27 sliding
layers to 9 full ones, which is a 3.4x discount a flat price would miss."""
from vllm_omni.edge.kv_budget import kv_budget_for
b = kv_budget_for(_published("XHToken/Spark-X2.5-4B"), max_model_len=32768)
assert (b.full_layers, b.sliding_layers, b.linear_layers) == (9, 27, 0)
# 36 layers x 4 KV heads x 256 x 2 (K and V) x 2 bytes = 144 KiB/token.
assert b.bytes_per_token_flat == 36 * 4 * 256 * 2 * 2 == 144 * 1024
assert b.saving_vs_flat > 3.3
@@ -0,0 +1,69 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
"""Omni-only forward kwargs must not be forced on a model that cannot take them.
The AR runner hands every stage ``sampling_metadata``, ``logits_index`` and
``sampler``, which omni-native models absorb through ``**kwargs``. A model vLLM
owns does not: ``LlamaForCausalLM.forward`` is
``(input_ids, positions, intermediate_tensors, inputs_embeds)`` and nothing
else, so passing the extras is a ``TypeError`` on the very first forward.
"""
from __future__ import annotations
import torch
from vllm_omni.worker.gpu_model_runner import OmniGPUModelRunner
class _OmniNativeModel(torch.nn.Module):
def forward(self, input_ids, positions, intermediate_tensors=None, inputs_embeds=None, **kwargs):
return input_ids
class _VLLMNativeModel(torch.nn.Module):
"""The shape of vLLM's own causal LMs: no ``**kwargs``."""
def forward(self, input_ids, positions, intermediate_tensors=None, inputs_embeds=None):
return input_ids
class _Probe:
"""Just enough of a runner to exercise the helper."""
def __init__(self, model):
self.model = model
_accepted_forward_kwargs = OmniGPUModelRunner._accepted_forward_kwargs
def test_a_model_taking_kwargs_is_left_alone():
assert _Probe(_OmniNativeModel())._accepted_forward_kwargs() is None
def test_a_vllm_native_model_reports_exactly_its_parameters():
accepted = _Probe(_VLLMNativeModel())._accepted_forward_kwargs()
assert accepted == frozenset(
{"input_ids", "positions", "intermediate_tensors", "inputs_embeds"}
)
for omni_only in ("sampling_metadata", "logits_index", "sampler"):
assert omni_only not in accepted
def test_the_answer_is_cached():
"""``inspect.signature`` on every decode step would be absurd."""
probe = _Probe(_VLLMNativeModel())
first = probe._accepted_forward_kwargs()
probe.model = _OmniNativeModel() # would change the answer if recomputed
assert probe._accepted_forward_kwargs() is first
def test_an_uninspectable_forward_falls_back_to_passing_everything():
"""Degrade to the previous behaviour rather than silently dropping
arguments a model may actually need."""
class Weird(torch.nn.Module):
forward = staticmethod(print) # no usable signature for our purposes
accepted = _Probe(Weird())._accepted_forward_kwargs()
assert accepted is None or "sampling_metadata" not in accepted