Run the same checks on Linux that the Windows scripts run
The product could only reach a GPU through one hard-coded route: `wsl.exe -d Ubuntu`, a device named "RTX 4090", and launch scripts that existed only as PowerShell. On this machine `WSL_DISTRO_NAME` is already set, so the local shell is Linux and the wsl.exe hop was unnecessary; on any other Linux host it is impossible. Every SGLang, vLLM and KTransformers profile was reported "missing" here even with a working 4090. profiles.py now asks the host what it is instead of assuming: `uses_wsl()` is false inside WSL and only true when wsl.exe is actually on PATH, `host_shell()` runs `bash -lc` directly or through `wsl.exe -d settings.wsl_distro`, `gpu_available()` replaced `wsl_gpu_available()`, and `launch_script()` picks the .sh twin on a Linux host and the .ps1 on a Windows one. The schema field `wsl_gpu` became `gpu_available` because the old name lied on Linux. Training no longer fails on a card name. `cuda_bf16_training()` gates on cuda_available plus bf16_supported, which the training environment already records, so an RTX 5090 or a 4080 passes and a non-BF16 4090 still fails. Fourteen .sh twins cover the six launch profiles plus install, verify, serve, download and finetune; the six WSL-hopping .ps1 files read ELY_EYE_WSL_DISTRO instead of Ubuntu. PowerShell parsing is not verified here because no pwsh exists on this host. ci.yml runs pytest, ruff, go build/vet/test/gofmt, the Vite build and a docker build-plus-curl on every push. To make that lint gate mean anything, the 17 pre-existing ruff findings across backend/src are cleared: 14 mechanical fixes plus three probe handlers that now name the failure families they absorb (OSError, SubprocessError, ValueError) instead of catching Exception. Verification: pytest 239 passed; ruff check backend/src bench clean (17 at HEAD); mypy on the 12 touched files 14 errors, identical at HEAD; pyright on the same files 8 errors, identical at HEAD; bash -n clean on all 15 .sh.
This commit is contained in:
1 parent
36f40c4c59
commit
922d01202f
34 files changed
+482
-88
No files matched your search
@@ -0,0 +1,102 @@
|
||||
"""The launch layer must describe the machine it runs on, not the one it was written on."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import stat
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from ely_eye import profiles
|
||||
from ely_eye.config import Settings
|
||||
from ely_eye.proofs.training_trace import cuda_bf16_training
|
||||
from ely_eye.training import require_cuda_bf16
|
||||
|
||||
|
||||
def _stub_nvidia_smi(tmp_path: Path, monkeypatch, output: str, exit_code: int = 0) -> None:
|
||||
bin_dir = tmp_path / "bin"
|
||||
bin_dir.mkdir()
|
||||
stub = bin_dir / "nvidia-smi"
|
||||
stub.write_text(f"#!/bin/sh\nprintf '%s\\n' '{output}'\nexit {exit_code}\n", encoding="utf-8")
|
||||
stub.chmod(stub.stat().st_mode | stat.S_IEXEC)
|
||||
monkeypatch.setenv("PATH", f"{bin_dir}{os.pathsep}{os.environ['PATH']}")
|
||||
|
||||
|
||||
def test_a_gpu_that_is_not_the_written_down_card_still_counts(tmp_path: Path, monkeypatch) -> None:
|
||||
_stub_nvidia_smi(tmp_path, monkeypatch, "GPU 0: NVIDIA GeForce RTX 5090 (UUID: GPU-1234)")
|
||||
monkeypatch.setattr(profiles, "uses_wsl", lambda: False)
|
||||
assert profiles.gpu_available(Settings(home=tmp_path / "home")) is True
|
||||
|
||||
|
||||
def test_a_machine_the_driver_cannot_see_reports_no_gpu(tmp_path: Path, monkeypatch) -> None:
|
||||
_stub_nvidia_smi(tmp_path, monkeypatch, "nvidia-smi: command not found", exit_code=127)
|
||||
monkeypatch.setattr(profiles, "uses_wsl", lambda: False)
|
||||
assert profiles.gpu_available(Settings(home=tmp_path / "home")) is False
|
||||
|
||||
|
||||
def test_the_distro_name_comes_from_settings(monkeypatch) -> None:
|
||||
monkeypatch.setattr(profiles, "uses_wsl", lambda: True)
|
||||
command = profiles.host_shell("true", Settings(home=Path("/tmp"), wsl_distro="Ubuntu-24.04"))
|
||||
assert command == ["wsl.exe", "-d", "Ubuntu-24.04", "bash", "-lc", "true"]
|
||||
|
||||
|
||||
def test_inside_wsl_the_local_shell_runs(monkeypatch, tmp_path: Path) -> None:
|
||||
monkeypatch.setenv("WSL_DISTRO_NAME", "Ubuntu")
|
||||
monkeypatch.setattr(profiles.shutil, "which", lambda name: "/mnt/c/WINDOWS/system32/wsl.exe")
|
||||
assert profiles.uses_wsl() is False
|
||||
monkeypatch.delenv("WSL_DISTRO_NAME")
|
||||
assert profiles.uses_wsl() is True
|
||||
assert profiles.host_shell("true", Settings(home=tmp_path / "home", wsl_distro="Ubuntu"))[0] == "wsl.exe"
|
||||
|
||||
|
||||
def test_a_linux_host_is_pointed_at_the_shell_twin(monkeypatch) -> None:
|
||||
monkeypatch.setattr(profiles, "uses_wsl", lambda: False)
|
||||
assert profiles.launch_script("scripts/launch-sglang-live.ps1") == "scripts/launch-sglang-live.sh"
|
||||
monkeypatch.setattr(profiles, "uses_wsl", lambda: True)
|
||||
assert profiles.launch_script("scripts/launch-sglang-live.ps1") == "scripts/launch-sglang-live.ps1"
|
||||
|
||||
|
||||
def test_the_training_verdict_does_not_name_a_card() -> None:
|
||||
newer = {"cuda_available": True, "bf16_supported": True, "device_name": "NVIDIA GeForce RTX 5090"}
|
||||
assert cuda_bf16_training(newer) is True
|
||||
older = {"cuda_available": True, "bf16_supported": True, "device_name": "NVIDIA GeForce RTX 4080"}
|
||||
assert cuda_bf16_training(older) is True
|
||||
without_bf16 = {"cuda_available": True, "bf16_supported": False, "device_name": "NVIDIA GeForce RTX 4090"}
|
||||
assert cuda_bf16_training(without_bf16) is False
|
||||
|
||||
|
||||
class _FakeCuda:
|
||||
def __init__(self, available: bool, bf16: bool) -> None:
|
||||
self._available = available
|
||||
self._bf16 = bf16
|
||||
|
||||
def is_available(self) -> bool:
|
||||
return self._available
|
||||
|
||||
def is_bf16_supported(self) -> bool:
|
||||
return self._bf16
|
||||
|
||||
|
||||
class _FakeTorch:
|
||||
def __init__(self, available: bool, bf16: bool) -> None:
|
||||
self.cuda = _FakeCuda(available, bf16)
|
||||
|
||||
|
||||
def test_training_refuses_a_machine_without_cuda_by_capability_not_card() -> None:
|
||||
with pytest.raises(RuntimeError) as refused:
|
||||
require_cuda_bf16(_FakeTorch(available=False, bf16=False))
|
||||
assert "4090" not in str(refused.value)
|
||||
require_cuda_bf16(_FakeTorch(available=True, bf16=True))
|
||||
|
||||
|
||||
def test_every_profile_ships_a_script_for_this_host(tmp_path: Path, monkeypatch) -> None:
|
||||
root = Path(__file__).resolve().parents[2]
|
||||
monkeypatch.setattr(profiles, "uses_wsl", lambda: False)
|
||||
linux = profiles.runtime_profile_report(Settings(home=tmp_path / "home"), root)
|
||||
assert [item.name for item in linux.validations if not item.script_exists] == []
|
||||
assert all(item.script.endswith(".sh") for item in linux.profiles), linux.profiles
|
||||
monkeypatch.setattr(profiles, "uses_wsl", lambda: True)
|
||||
windows = profiles.runtime_profile_report(Settings(home=tmp_path / "home"), root)
|
||||
assert [item.name for item in windows.validations if not item.script_exists] == []
|
||||
assert all(item.script.endswith(".ps1") for item in windows.profiles), windows.profiles
|
||||
Reference in new issue
Block a user