# Hardware detection and simulation whichllm detects the current machine and can also simulate hardware for purchase planning. The source of truth is the `hardware/` package plus curated registry data in `data/gpu.py`. `constants.py` remains as a compatibility export layer for older imports. ## Detected data The ranker receives a `HardwareInfo` object with: - GPU list - CPU name - physical CPU cores - AVX2 and AVX-512 support - total RAM - free disk space - OS name Each GPU is represented as `GPUInfo`: - name - vendor - VRAM bytes - usable VRAM bytes, when a runtime headroom is active - NVIDIA compute capability, when known - CUDA or ROCm version, when known - memory bandwidth estimate - whether the GPU uses shared memory ## NVIDIA NVIDIA detection tries `nvidia-ml-py` first. If NVML is unavailable, fails to initialize, or returns no devices, whichllm falls back to: ```bash nvidia-smi --query-gpu=name,memory.total,clocks.max.memory --format=csv,noheader,nounits ``` If a driver rejects `clocks.max.memory`, whichllm retries the older `name,memory.total` query. For known cards, curated data and strict `dbgpu` lookups provide: - memory bandwidth - compute capability The max memory clock is used when a marketing name covers multiple memory types. For example, GTX 1650 GDDR5 and GDDR6 cards share the same broad driver name, so whichllm uses the reported memory clock when available and falls back to the conservative bandwidth when it is not. DGX Spark / NVIDIA GB10 uses unified system memory. When the driver reports `memory.total` as unavailable, whichllm treats GB10 as shared memory and uses system RAM for fit checks. Compute capability is used to warn when a card is below the minimum expected by common local inference tools. ## AMD On Linux, AMD detection tries `rocm-smi` first: - product name - VRAM - ROCm driver version If `rocm-smi` is unavailable, it falls back to `lspci` and then `/sys/class/drm`. On Windows, whichllm uses `Win32_VideoController` as a fallback for AMD GPUs. When possible, it also reads the 64-bit dedicated-memory value from the `Control\Video` registry path because `AdapterRAM` is a 32-bit field and can cap larger cards around 4 GB. AMD shared-memory APUs are treated differently from discrete GPUs. Names such as Strix Halo, Ryzen AI MAX, Radeon 8050S, Radeon 8060S, Radeon 890M, and Radeon 780M are modeled as shared-memory systems. If the reported VRAM is just a small aperture, whichllm uses the system memory pool for fit checks instead of treating it as a tiny discrete GPU. ## Intel Intel integrated GPUs are detected on Linux through `lspci` or sysfs, and on Windows through `Win32_VideoController`. They do not normally report dedicated VRAM, so whichllm records them with `0` dedicated VRAM and labels them as shared memory. Discrete Intel Arc cards are kept as dedicated-memory GPUs when the device name and memory report look like a discrete adapter. The Intel backend factor is lower than NVIDIA, AMD, and Apple because local LLM GPU inference support is less mature. ## Apple Silicon On macOS, whichllm uses: ```bash system_profiler SPHardwareDataType -json ``` Apple Silicon uses unified memory, so the detected chip memory is treated as available GPU memory. Memory bandwidth is looked up by chip family when known. Partial offload on Apple Silicon is not penalized like discrete PCIe offload. Weights still live in unified memory, so the speed penalty is milder. ## CPU and memory CPU detection reads: - `/proc/cpuinfo` on Linux - `sysctl` on macOS - `wmic` on Windows, then PowerShell / CIM when `wmic` is unavailable or only returns a header Physical core count comes from `psutil`, with a Linux `/proc/cpuinfo` fallback. RAM comes from `psutil.virtual_memory()`. Disk free space is checked under the user's home directory by default. ## GPU simulation Use `--gpu` to simulate a GPU: ```bash whichllm --gpu "RTX 4090" whichllm hardware --gpu "Apple M3 Max" whichllm upgrade "RTX 4090" "RTX 5090" "H100" ``` Simulation uses the `dbgpu` package for a TechPowerUp-backed GPU database. whichllm adds extra handling for common aliases and Apple Silicon chips because those are not covered by dbgpu. Use `--vram` when a GPU name is ambiguous, unknown, or has multiple variants: ```bash whichllm --gpu "RTX 5060 Ti" --vram 16 whichllm hardware --gpu "Unknown GPU" --vram 24 ``` For detected integrated or unified-memory GPUs, use `--vram` and `--bandwidth` / `--ram-bandwidth` to override the automatically detected usable capacity and memory bandwidth: ```bash whichllm --vram 8 --ram-bandwidth 68 whichllm hardware --vram 8 --bandwidth 68 ``` If multiple GPUs are detected, pass `--gpu-index` to choose the GPU shown by `whichllm hardware`: ```bash whichllm --gpu-index 1 --vram 8 --ram-bandwidth 68 ``` By default, whichllm applies a small automatic VRAM headroom before fit checks. This avoids recommending models that only fit on paper but overflow in runtimes that need extra graph buffers or loader overhead. Tune it with: ```bash whichllm --vram-headroom 1.5GB whichllm --vram-headroom 10% whichllm --vram-headroom none ``` Multi-GPU simulation accepts repeated flags, comma-separated values, and count shorthand: ```bash whichllm --gpu "2x RTX 4090" whichllm --gpu "RTX 4090" --gpu "RTX 3090" whichllm --gpu "RTX 4090, RTX 3090" ``` `--vram` is only supported for a single simulated GPU. For multi-GPU simulation, use known GPU names so whichllm can resolve each card's VRAM from the GPU database. ## Fit types Compatibility checks classify a candidate into one of three fit types: | Fit | Meaning | | --- | --- | | `full_gpu` | Required memory fits in available GPU memory | | `partial_offload` | GPU plus usable system RAM can hold the model | | `cpu_only` | Usable system RAM can hold the model without GPU | If neither GPU memory nor usable RAM can hold the model, the candidate is not ranked. whichllm keeps a bounded system-RAM reserve for the OS and other processes. Use `--ram-budget available` to cap partial-offload planning to the current available RAM reported by the OS, or pass a fixed budget such as `--ram-budget 8GB`. ## Multiple GPUs For fit checks, whichllm uses a conservative multi-GPU budget rather than pretending all VRAM is one perfect device. It starts from raw total VRAM, applies a small per-GPU overhead, and then applies a utilization factor. Homogeneous sets receive a less severe reduction than heterogeneous sets. If a dedicated GPU is present, low-aperture shared-memory integrated GPUs are not added to the fit pool. This avoids treating unrelated system RAM and dedicated VRAM as one full-GPU target. For speed estimates, whichllm uses the largest detected GPU as the representative device and marks multi-GPU speed as low-confidence. This avoids claiming ideal scaling when real performance depends on backend split mode, PCIe/NVLink bandwidth, NCCL/RCCL support, batch size, and model architecture. This is a practical fit approximation. It does not model every tensor-parallel or pipeline-parallel runtime configuration. ## Disk checks The compatibility check also compares estimated model weight size with free disk space. If the model cannot be downloaded, it is marked unrunnable. ## Known limitations - GPU bandwidth is a lookup or database estimate, not a live benchmark. - Speed estimates are planning numbers. The default table and JSON fields such as `speed_confidence` and `speed_range_tok_per_sec` show uncertainty. - Driver, runtime, batch size, prompt length, and thermal limits can change real performance. - Multi-GPU runtime behavior depends on the inference backend and is only approximated. - Apple and shared-memory APU behavior is modeled as unified-memory style, but real results still depend on OS pressure and memory bandwidth.