#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct SimdCaps {
pub avx2: bool,
pub avx512f: bool,
pub fma: bool,
pub neon: bool,
}
impl SimdCaps {
pub fn detect() -> Self {
#[cfg(target_arch = "x86_64")]
{
SimdCaps {
avx2: is_x86_feature_detected!("avx2"),
avx512f: is_x86_feature_detected!("avx512f"),
fma: is_x86_feature_detected!("fma"),
neon: false,
}
}
#[cfg(target_arch = "aarch64")]
{
SimdCaps {
avx2: false,
avx512f: false,
fma: false,
neon: std::arch::is_aarch64_feature_detected!("neon"),
}
}
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
{
SimdCaps::default()
}
}
pub fn label(&self) -> &'static str {
if self.avx2 && self.fma {
"AVX2+FMA (ferrox's fastest implemented CPU kernel)"
} else if self.neon {
"NEON (ferrox Q4_K/Q6_K/Q8_0/Q4_0 fused dots live)"
} else {
"scalar (no SIMD kernel available for this host)"
}
}
}
#[derive(Debug, Clone)]
pub struct HardwareProfile {
pub cpu_logical_cores: usize,
pub host_ram_total_bytes: u64,
pub simd: SimdCaps,
pub cuda_available: bool,
pub cuda_device_count: usize,
pub cuda_device_name: Option<String>,
pub cuda_vram_total_bytes: u64,
pub cuda_vram_free_bytes: u64,
}
impl HardwareProfile {
pub fn detect() -> Self {
let cpu_logical_cores = std::thread::available_parallelism()
.map(|n| n.get())
.unwrap_or(1);
let host_ram_total_bytes = detect_total_ram_bytes();
let simd = SimdCaps::detect();
#[cfg(feature = "cuda")]
let (
cuda_available,
cuda_device_count,
cuda_device_name,
cuda_vram_total_bytes,
cuda_vram_free_bytes,
) = {
match crate::gpu::probe() {
Some(info) => (
true,
info.device_count,
info.first_device_name,
info.total_vram_bytes,
info.free_vram_bytes,
),
None => (false, 0, None, 0, 0),
}
};
#[cfg(not(feature = "cuda"))]
let (
cuda_available,
cuda_device_count,
cuda_device_name,
cuda_vram_total_bytes,
cuda_vram_free_bytes,
) = (false, 0, None, 0, 0);
HardwareProfile {
cpu_logical_cores,
host_ram_total_bytes,
simd,
cuda_available,
cuda_device_count,
cuda_device_name,
cuda_vram_total_bytes,
cuda_vram_free_bytes,
}
}
}
fn detect_total_ram_bytes() -> u64 {
#[cfg(target_os = "linux")]
{
if let Ok(contents) = std::fs::read_to_string("/proc/meminfo") {
for line in contents.lines() {
if let Some(rest) = line.strip_prefix("MemTotal:") {
let kb: u64 = rest
.trim()
.trim_end_matches(" kB")
.trim()
.parse()
.unwrap_or(0);
return kb * 1024;
}
}
}
0
}
#[cfg(target_os = "macos")]
{
std::process::Command::new("sysctl")
.args(["-n", "hw.memsize"])
.output()
.ok()
.and_then(|out| String::from_utf8(out.stdout).ok())
.and_then(|s| s.trim().parse().ok())
.unwrap_or(0)
}
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
{
0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn detect_never_panics_and_reports_at_least_one_core() {
let profile = HardwareProfile::detect();
assert!(profile.cpu_logical_cores >= 1);
}
#[test]
fn detect_reports_plausible_ram_on_linux_or_macos() {
let profile = HardwareProfile::detect();
if profile.host_ram_total_bytes > 0 {
assert!(profile.host_ram_total_bytes > 128 * 1024 * 1024);
}
}
#[test]
fn simd_caps_label_is_never_empty() {
let caps = SimdCaps::detect();
assert!(!caps.label().is_empty());
}
#[test]
#[cfg(not(feature = "cuda"))]
fn without_cuda_feature_profile_always_reports_no_cuda() {
let profile = HardwareProfile::detect();
assert!(!profile.cuda_available);
assert_eq!(profile.cuda_device_count, 0);
assert_eq!(profile.cuda_device_name, None);
assert_eq!(profile.cuda_vram_free_bytes, 0);
}
}