Hardware probe
HardwareProbe.probe() (hal0.hardware.probe) writes a snapshot to
/etc/hal0/hardware.json on install, on hal0 config hardware --refresh, and from the dashboard’s re-probe button. All probing is
subprocess/sysfs-based and never raises.
| Signal | Source |
|---|---|
| CPU model/cores/threads | /proc/cpuinfo, with an ARM fallback chain (Hardware/Model/CPU part fields), last-resort platform.machine(). |
| RAM total/available | /proc/meminfo (MemTotal/MemAvailable). |
| GPU (AMD) | DRM sysfs scan of /sys/class/drm/card*/device/mem_info_vram_total. |
| Hostname | /proc/sys/kernel/hostname. |
The result is validated against the HardwareInfo schema — see the
hardware.json section of Config schema for the
full field list, including unified_memory_mb (the true UMA pool — use this, not
ram_mb + vram_mb, on unified-memory systems like Strix Halo) and platform
(strix-halo, wsl2, proxmox-kvm, kvm, lxc, bare-metal-*, unknown).
Canonical device taxonomy
hal0.model_meta is the single source of truth for device ids (previously duplicated
across 5 call sites, now unified). DEFAULT_DEVICE = "gpu-rocm".
| Device id | Label | Recommended | Default profile | Notes |
|---|---|---|---|---|
gpu-rocm |
GPU (ROCm) | chat |
Best throughput on Strix Halo — the recommended default. | |
gpu-vulkan |
GPU (Vulkan) | — | chat |
Runs anywhere Mesa Vulkan does, and needs only a render node — so it is the lane for a box with no /dev/kfd. It is not the seeded default for maturity reasons, not speed ones. LLM slots on this device are gated on a runner image whose digest is Vulkan-gated in manifest.json (#1888/#1948). Also the device the non-llama.cpp Vulkan runtimes use (Kokoro, ComfyUI). |
gpu-cuda |
GPU (CUDA) | — | chat |
NVIDIA GPUs via llama.cpp CUDA — experimental on hal0. |
cpu |
CPU | — | cpu-chat |
Always available, slow but correct. |
npu |
NPU (FLM) | — | flm |
AMD XDNA NPU via FastFlowLM — chat/embed/ASR trio on one process. |
VALID_DEVICES is the frozenset of these 5 ids. A legacy v0.1 backend enum
(rocm|vulkan|cuda|cpu|flm|moonshine|kokoro) is deprecated and round-trips for one
release; map_backend_to_device() maps unknown legacy values to "cpu" as a safe
fallback rather than crashing config load.
Backend-selection decision tree
hardware.recommend._backend_for() — this is the actual logic the installer and
dashboard use to pick a device for a new slot, given a probed HardwareInfo:
- AMD,
compute_capable(rocm-smi reachable) or/dev/kfdpresent →
ROCm. The rationale string still names the “AMD UMA / Strix Halo class”
when unified memory ≥ 32 GB andvram_mb <= 4096(a small dedicated VRAM
number is a UMA signal, not a real cap). Note this is a maturity
preference, not a throughput one — see the lane comparison below. - AMD, no ROCm compute node but a Vulkan-capable GPU → Vulkan. This
is the unprivileged-LXC shape: a working iGPU with no/dev/kfdforwarded.
The lane is real, but an LLM slot on it must resolve a runner image whose
digest has"vulkan"in itslanes_gatedpin inmanifest.json, or slot
load refuses it by name (#1888/#1948) — an ungated Vulkan backend can emit
invalid tokens for every model. - AMD, neither ROCm compute nor a usable Vulkan device → CPU.
- NVIDIA, NVIDIA Container Toolkit present (
nvidia-ctkonPATHor a CDI spec
under/etc/cdi//var/run/cdi) → CUDA. - NVIDIA, no CDI → Vulkan fallback.
- Intel iGPU / unknown-but-
vulkan_capable→ Vulkan. - No GPU detected → CPU (“no GPU detected — CPU inference only, slow but
correct”).
ROCm vs Vulkan on AMD
Both lanes run the same Standard runner image. Throughput figures for a pinned
digest come from the runner-images hardware gate that admits it; measure your
own box with hal0 bench.
hal0 still seeds gpu-rocm on a box that can run it. The reasons are
maturity, not speed:
- the ROCm lane carries hal0’s whole validation history — every release
candidate has been exercised on it; - MTP / speculative-decode profiles are tuned against the ROCm lane, and those
gains are not represented in a plain pp512/tg128 comparison; - the Vulkan lane is admitted per digest by the hardware gate.
The seeded default is an open question, revisited at GA against a broader
matrix. If your workload is plain prefill/decode on Strix Halo, switching is
a defensible thing to do today — see the “Switching a slot to the Vulkan
lane” section of Manage slots.
VRAM budget (_vram_budget_gb()): AMD UMA → half of the unified pool; discrete GPU →
vram_mb; CPU-only → half of ram_available_mb.
Platform support
HardwareInfo.platform enumerates every platform hal0 recognizes during probing:
strix-halo, wsl2, proxmox-kvm, kvm, lxc, bare-metal-amd-gpu,
bare-metal-nvidia-gpu, bare-metal-intel-igpu, bare-metal-cpu-only, unknown.
For install-target-specific setup (Proxmox LXC, WSL2, bare-metal Ubuntu), see the
Getting Started guides — this page covers only the hardware-detection and
backend-selection logic, not per-platform install steps.
See also
- Providers, profiles & devices — how a
device selection flows into a slot’sdevicefield. - Model roster & benchmarks — how hardware
tier drives the curated primary-slot model recommendation.