Skip to main content

Crate flodl_hw

Crate flodl_hw 

Source
Expand description

Hardware detection for flodl: GPUs and host RAM, with no libtorch and no CUDA runtime.

One dependency, serde_json, and only to read ENV_TESTING_GPU_JSON. It is free in practice: every consumer (flodl, flodl-cli, flodl-hf) already depends on it directly, so a workspace build and a cargo install flodl-cli compile exactly zero extra crates for it.

§Why this is its own crate

Two consumers need the same answers and cannot share code any other way:

  • flodl needs GPU identity before libtorch is initialized. flodl’s CUDA APIs (e.g. flodl::tensor::gpu_device_count) initialize libtorch on first call, and once libtorch latches onto a device list, CUDA_VISIBLE_DEVICES is ignored. Critically for cluster mode, the launcher’s spawned children then inherit a corrupted CUDA context on heterogeneous-GPU rigs. See the “no CUDA before Trainer::run” invariant.
  • fdl (flodl-cli) needs the same answers before libtorch exists at all, to decide which libtorch variant to download or build. It therefore cannot depend on flodl, which would pull flodl-sys and libtorch onto the install path.

Both used to carry a hand-synchronized copy of the same struct and the same parser, kept aligned by a comment. This crate is the single source, and the one place a second GPU vendor is added.

§Two enumerations, deliberately

detect_gpus reports what the runtime will see (visibility masks applied). detect_gpus_physical reports what is installed (masks ignored). Provisioning decisions want the physical set; runtime decisions want the visible set. Conflating them is a real bug in both directions, so they are named apart rather than separated by a boolean argument.

§A sweep returns findings, it does not print them

Both of the above are shorthands for survey / survey_visible, which return a GpuSurvey: the devices plus what the sweep learned that a device list cannot express. An empty list has at least four causes needing different responses (CPU-only box, driver present but tool broken, card present but stack not installed, masked away), and the one that matters most for a second vendor is the third: an AMD card with no ROCm is a common state and the user needs told, with an action.

Detection therefore records SurveyNotes and lets the caller decide what to surface, rather than eprintln!ing from inside a library. GpuSurvey::require_devices turns an empty sweep into the best available explanation, which is what a command with an explicit GPU request (--gpus all) wants.

§Vendor is not device

GpuVendor is an identity. It is deliberately not the device string a tensor library is handed: ROCm libtorch keeps kCUDA, so an AMD device is GpuVendor::Amd here while still being addressed as CUDA at the API surface. Vendor drives detection, diagnostics, packaging and feature derivation; the API surface is a different axis, and assuming they are the same one does not survive contact with Intel (whose libtorch device type genuinely differs).

§Spoofing hardware for tests

ENV_TESTING_GPU_JSON replaces the whole sweep with a described one, so a second vendor’s detection, libtorch variant selection and per-host build routing are testable on a machine that has none of that hardware. See testing for the format.

§Contract

No thread is spawned and no GPU runtime is initialized. Every probe is a filesystem read or a bounded subprocess, and each vendor’s subprocess is gated behind cheap filesystem checks, so a CPU-only box spawns nothing at all. Absent hardware is never an error, so callers need no “did we have a driver” branch. The one panic is a malformed ENV_TESTING_GPU_JSON, which is a developer error in a deliberately-set variable.

Re-exports§

pub use testing::ENV_TESTING_GPU_JSON;

Modules§

testing
Hardware spoofing for tests: ENV_TESTING_GPU_JSON.

Structs§

GpuInfo
One GPU’s identity, capability and VRAM.
GpuSurvey
The result of sweeping a machine for GPUs.
MemInfo
Host RAM snapshot: total and currently-available bytes.
SurveyNote
One finding from a sweep: a fact the device list cannot express.

Enums§

GpuArch
A device’s architecture token, in whatever shape its vendor uses.
GpuVendor
Which GPU stack a device belongs to.
NoteKind
Why a survey has something to say beyond its device list.
VariantClass
What a libtorch variant label says about its backend.

Functions§

classify_variant_label
Classify a libtorch variant label (precompiled/cu128, builds/sm61-sm120, rocm70, …) by its basename.
cpu_package_count
How many CPU packages (sockets) the kernel reports, or None off Linux / when the topology is not exposed.
detect_gpus
Enumerate the GPUs the runtime will see. Shorthand for survey_visible when the caller does not need the findings.
detect_gpus_for
Enumerate the visible devices this build can address. Shorthand for survey_visible_for when the caller does not need the findings.
detect_gpus_physical
Enumerate every installed GPU, ignoring visibility masks. Shorthand for survey when the caller does not need the findings.
mem_info
Read host RAM totals from /proc/meminfo.
nvidia_driver_version
NVIDIA driver version string, or None when nvidia-smi is absent or errors.
rocm_runtime_lib_dir
The runtime’s library directory (<root>/lib or <root>/lib64, whichever holds libhsa-runtime64). This is the value LD_LIBRARY_PATH needs, and it is resolved here rather than composed by callers because lib vs lib64 is a distro property the caller cannot guess: composing <root>/lib on a lib64 layout produces a path the loader silently skips, which hands the loader libtorch’s bundled ROCm stack — the exact segfault the ordering fix exists to prevent.
rocm_runtime_root
Locate a ROCm userspace installation, or None.
survey
Sweep the machine for GPUs, ignoring visibility masks.
survey_visible
Sweep the machine and apply the visibility masks, reporting what the runtime will actually see.
survey_visible_for
survey_visible, narrowed to the one vendor a caller can actually address.