--- name: Core hardware probe type: architecture-map-page slice: 05-core-storage-hotkey-build last_verified: 2026/05/09 --- # Core hardware probe > **Where you are:** [Architecture map](../README.md) → [Core, Storage, Hotkey, Build](README.md) → Core hardware probe **Plain English summary.** What CPU, RAM, GPU, and operating system the user has. The probe runs once at app startup so the recommendation engine can pick the right speech model. CPU feature flags (AVX2, FMA, NEON) are also surfaced so the runtime can warn users on pre-AVX2 silicon that performance will be a fraction of expected. ## At a glance - File: `crates/core/src/hardware.rs` (261 LOC). - External deps: `sysinfo 0.35`, `libloading 0.8` (Vulkan probe). - Public surface: `SystemProfile`, `CpuInfo`, `CpuFeatures`, `GpuInfo`, `GpuVendor`, `GpuAcceleration`, `Os`, `probe_system`, `probe_cpu_features`, `probe_gpu`, `probe_os`, `vulkan_loader_available`. - Consumers: slice 2 (runtime-capabilities banner), [`core-recommendation.md`](core-recommendation.md), slices 3 + 4 (`vulkan_loader_available` to gate Vulkan acceleration). ## What's in here ### `SystemProfile` — `crates/core/src/hardware.rs:7` ```rust pub struct SystemProfile { pub ram: Megabytes, pub cpu: CpuInfo, pub gpu: Option, pub os: Os, } ``` Top-level snapshot. Built by `probe_system()`. ### `CpuInfo` and `CpuFeatures` — `crates/core/src/hardware.rs:14, 30` ```rust pub struct CpuInfo { pub logical_processors: usize, pub brand: String, pub features: CpuFeatures, } pub struct CpuFeatures { pub avx2: bool, pub avx512f: bool, pub fma: bool, pub sse4_2: bool, pub neon: bool, } ``` `CpuFeatures::has_ggml_baseline` (`hardware.rs:41`) returns `true` when the CPU has the baseline that `ggml` (whisper.cpp / llama.cpp) expects: `avx2 && fma` on x86_64, `neon` on aarch64. When `false`, the runtime banner fires (slice 2). Reference: `whisper-rs` issues #8 and #117 (illegal instruction on pre-AVX2 CPUs). ### `probe_cpu_features()` — `crates/core/src/hardware.rs:59` `std::is_x86_feature_detected!` lowers to runtime CPUID. On aarch64, NEON is the architectural baseline so it is always reported as `true`. On other targets all flags are `false`. ### GPU types — `crates/core/src/hardware.rs:84-105` ```rust pub struct GpuInfo { pub vendor: GpuVendor, pub vram: Megabytes, pub acceleration: GpuAcceleration, } pub enum GpuVendor { Nvidia, Amd, Intel, Apple, Unknown } pub struct GpuAcceleration { pub cuda: bool, pub metal: bool, pub vulkan: bool } ``` ### `Os` — `crates/core/src/hardware.rs:107` ```rust pub enum Os { Windows, Linux, MacOs, Ios, Android } ``` Resolved at runtime via `cfg!(target_os = ...)` in `probe_os()`. Unsupported targets default to `Linux`. ### `probe_system()` — `crates/core/src/hardware.rs:162` The composed probe. Builds a single `sysinfo::System::new_all()` (which is expensive on Windows and macOS), then derives RAM, CPU, GPU, and OS from it. Calling the individual probes one-by-one would re-walk `/proc` per call. ### `probe_gpu()` — `crates/core/src/hardware.rs:135` **Stub.** Returns `None` today. The intended implementation routes through `wgpu` for vendor / VRAM detection and a platform-specific path (NVML on NVIDIA, Metal API on macOS) for acceleration flags. See [Open questions](#open-questions). ### `vulkan_loader_available()` — `crates/core/src/hardware.rs:183` Best-effort probe for the Vulkan loader shared library. Whisper.cpp and llama.cpp Vulkan backends silently fall back to CPU if the loader is missing at runtime. `libloading::Library::new` on candidates: - Linux: `libvulkan.so.1`, `libvulkan.so` - Windows: `vulkan-1.dll` - macOS: `libvulkan.1.dylib`, `libMoltenVK.dylib` A successful open means the loader is resolvable. Moved from `src-tauri/src/commands/models.rs` so non-Tauri crates (transcription, llm) can call it without depending on the Tauri binary. ## Tests `crates/core/src/hardware.rs:206-261`: - `probe_cpu_features_runs_without_panicking` — smoke. - `probe_system_populates_cpu_features` — asserts `CpuFeatures` is wired into the profile. - `ggml_baseline_matches_x86_64_rule` — verifies the `avx2 && fma` rule on x86, falls through gracefully on non-x86. - `ggml_baseline_requires_both_avx2_and_fma` — negative test (avx2 alone insufficient). - `vulkan_loader_available_does_not_panic` — smoke; cannot assert the boolean, depends on host. ## Watch-outs - **`probe_gpu()` returns `None`.** Recommendation scoring still works because `score_model` checks `if let Some(gpu) = ...` and gracefully scores zero-bonus when missing. But every accelerator-aware code path is conservative until this is implemented. - **`probe_system()` is expensive on Windows.** ~10-50 ms on the cold path because `System::new_all()` queries every WMI category. Call once at startup, cache the result in Tauri-managed state. - **`vulkan_loader_available()` calls `unsafe { libloading::Library::new }`.** Safe by audit: the handle is dropped at the end of the iteration without any symbol calls. Documented inline at `hardware.rs:194`. ## Open questions - **GPU probe is a stub.** Tracked in the slice debt section of [`README.md`](README.md). Until it lands, no code path can distinguish NVIDIA / AMD / Intel / Apple at runtime. - **No PCI / DRM enumeration on Linux.** `wgpu::Adapter::get_info` would give us vendor + name on every supported platform but pulls a heavy dep. Worth weighing against a smaller crate (`pci-ids`?) for the Linux-only path. ## See also - [Constants module](core-constants.md) - [Power-state probe](core-power.md) - [Inference thread tuning](core-tuning.md) - [Model registry](core-model-registry.md) - [Recommendation scoring](core-recommendation.md)