use crate::cpu::ArchInfo;
use crate::report::CpuReport;
use std::process::Command;
pub struct BsdCpuInfo {
model: String,
vendor: String,
logical_cores: u32,
max_mhz: Option<f32>,
arch_info: ArchInfo,
}
fn sysctl(key: &str) -> Option<String> {
let output = Command::new("sysctl").arg("-n").arg(key).output().ok()?;
if !output.status.success() {
return None;
}
let s = String::from_utf8_lossy(&output.stdout).trim().to_string();
if s.is_empty() { None } else { Some(s) }
}
impl BsdCpuInfo {
pub fn new() -> Result<Self, String> {
let model = sysctl("hw.model").ok_or_else(|| "sysctl hw.model failed".to_string())?;
let logical_cores = sysctl("hw.ncpu").and_then(|s| s.parse().ok()).unwrap_or(1);
let max_mhz = sysctl("hw.cpuspeed")
.or_else(|| {
sysctl("dev.cpu.0.freq_levels")
.and_then(|s| s.split('/').next().map(|s| s.to_string()))
})
.or_else(|| sysctl("hw.clockrate"))
.and_then(|s| s.parse::<f32>().ok());
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
let arch_info = crate::cpu::x86::detect();
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
let arch_info = ArchInfo {
vendor: None,
uarch: None,
soc: crate::cpu::arm::soc_from_hint(&model).map(|s| s.to_string()),
process_nm: None,
features: Vec::new(),
};
#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
let arch_info = crate::cpu::ppc::detect_from_name_str(&model);
#[cfg(not(any(
target_arch = "x86",
target_arch = "x86_64",
target_arch = "arm",
target_arch = "aarch64",
target_arch = "powerpc",
target_arch = "powerpc64"
)))]
let arch_info = ArchInfo::default();
let vendor = arch_info.vendor.clone().unwrap_or_else(|| {
let lower = model.to_lowercase();
if lower.contains("intel") {
"Intel".to_string()
} else if lower.contains("amd") {
"AMD".to_string()
} else if lower.contains("arm") || lower.contains("aarch64") {
"ARM".to_string()
} else {
"Unknown".to_string()
}
});
Ok(Self {
model,
vendor,
logical_cores,
max_mhz,
arch_info,
})
}
pub fn to_report(&self) -> CpuReport {
let info = &self.arch_info;
CpuReport {
model: self.model.clone(),
vendor: info.vendor.clone().unwrap_or_else(|| self.vendor.clone()),
uarch: info.uarch.clone(),
soc: info.soc.clone(),
technology_nm: info.process_nm,
architecture: std::env::consts::ARCH.to_string(),
physical_cores: self.logical_cores,
logical_cores: self.logical_cores,
max_ghz: self.max_mhz.map(|mhz| mhz / 1000.0),
base_ghz: None,
l1i_kb: None,
l1d_kb: None,
l2_kb: None,
l3_kb: None,
flags: info.features.clone(),
}
}
}