#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BlasKind {
OpenBlas,
IntelMkl,
Blis,
Accelerate,
Unknown,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CpuVendor {
Amd,
Intel,
Apple,
Unknown,
}
impl std::fmt::Display for BlasKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::OpenBlas => write!(f, "OpenBLAS"),
Self::IntelMkl => write!(f, "Intel MKL"),
Self::Blis => write!(f, "BLIS/AOCL"),
Self::Accelerate => write!(f, "Apple Accelerate"),
Self::Unknown => write!(f, "pure Rust (no external BLAS)"),
}
}
}
impl std::fmt::Display for CpuVendor {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Amd => write!(f, "AMD"),
Self::Intel => write!(f, "Intel"),
Self::Apple => write!(f, "Apple"),
Self::Unknown => write!(f, "unknown"),
}
}
}
#[must_use]
pub fn detect_cpu_vendor() -> CpuVendor {
#[cfg(target_os = "macos")]
return CpuVendor::Apple;
#[cfg(target_os = "linux")]
{
if let Ok(cpuinfo) = std::fs::read_to_string("/proc/cpuinfo") {
if cpuinfo.contains("AuthenticAMD") {
return CpuVendor::Amd;
}
if cpuinfo.contains("GenuineIntel") {
return CpuVendor::Intel;
}
}
CpuVendor::Unknown
}
#[cfg(not(any(target_os = "macos", target_os = "linux")))]
CpuVendor::Unknown
}
#[must_use]
pub fn detect_blas() -> BlasKind {
#[cfg(target_os = "macos")]
{
BlasKind::Accelerate
}
#[cfg(target_os = "linux")]
{
use std::ffi::CString;
let probe = |symbol: &str| -> bool {
let c_sym = CString::new(symbol).expect("BLAS symbol contains NUL byte");
#[expect(unsafe_code, reason = "dlsym probe for BLAS detection")]
unsafe {
!libc::dlsym(libc::RTLD_DEFAULT, c_sym.as_ptr()).is_null()
}
};
if probe("bli_info_get_version_str") {
return BlasKind::Blis;
}
if probe("mkl_get_version") {
return BlasKind::IntelMkl;
}
if probe("openblas_get_config") {
return BlasKind::OpenBlas;
}
BlasKind::Unknown
}
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
{
BlasKind::Unknown
}
}
#[must_use]
pub fn recommend_blas() -> Option<String> {
let blas = detect_blas();
let cpu = detect_cpu_vendor();
match (cpu, blas) {
(CpuVendor::Amd, BlasKind::OpenBlas) => Some(
"tip: AOCL-BLAS is 10-15% faster than OpenBLAS on AMD CPUs. \
Install: https://developer.amd.com/amd-aocl/"
.to_string(),
),
(CpuVendor::Amd, BlasKind::IntelMkl) => Some(
"warning: Intel MKL is intentionally slow on AMD CPUs (CPUID check). \
Use AOCL-BLAS or OpenBLAS instead."
.to_string(),
),
(CpuVendor::Intel, BlasKind::OpenBlas) => Some(
"tip: Intel MKL is faster than OpenBLAS on Intel CPUs. \
Install: sudo apt install libmkl-dev"
.to_string(),
),
(CpuVendor::Amd, BlasKind::Unknown) => Some(
"warning: no BLAS library detected — CPU inference will be slow. \
Install: sudo apt install libopenblas-dev (or AOCL-BLAS for best AMD performance)"
.to_string(),
),
(CpuVendor::Intel, BlasKind::Unknown) => Some(
"warning: no BLAS library detected — CPU inference will be slow. \
Install: sudo apt install libmkl-dev"
.to_string(),
),
(_, BlasKind::Unknown) => Some(
"warning: no BLAS library detected — CPU inference will be slow. \
Install: sudo apt install libopenblas-dev"
.to_string(),
),
_ => None,
}
}