use crate::{
BatteryInfo, CPUInfo, GPUInfo, HardwareQueryError,
MemoryInfo, NetworkInfo, NPUInfo, PCIDevice, Result, StorageInfo, ThermalInfo, TPUInfo, USBDevice,
ARMHardwareInfo, FPGAInfo, PowerProfile, VirtualizationInfo,
};
use serde::{Deserialize, Serialize};
use std::time::{SystemTime, UNIX_EPOCH};
use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HardwareInfo {
pub timestamp: u64,
pub cpu: CPUInfo,
pub gpus: Vec<GPUInfo>,
pub npus: Vec<NPUInfo>,
pub tpus: Vec<TPUInfo>,
pub arm_hardware: Option<ARMHardwareInfo>,
pub fpgas: Vec<FPGAInfo>,
pub memory: MemoryInfo,
pub storage_devices: Vec<StorageInfo>,
pub network_interfaces: Vec<NetworkInfo>,
pub battery: Option<BatteryInfo>,
pub thermal: ThermalInfo,
pub pci_devices: Vec<PCIDevice>,
pub usb_devices: Vec<USBDevice>,
pub power_profile: Option<PowerProfile>,
pub virtualization: VirtualizationInfo,
}
impl HardwareInfo {
pub fn query() -> Result<Self> {
let timestamp = SystemTime::now()
.duration_since(UNIX_EPOCH)
.map_err(|e| HardwareQueryError::unknown(format!("Failed to get timestamp: {e}")))?
.as_secs();
Ok(Self {
timestamp,
cpu: CPUInfo::query()?,
gpus: GPUInfo::query_all()?,
npus: NPUInfo::query_all()?,
tpus: TPUInfo::query_all()?,
arm_hardware: ARMHardwareInfo::detect().ok().flatten(),
fpgas: FPGAInfo::detect_fpgas().unwrap_or_default(),
memory: MemoryInfo::query()?,
storage_devices: StorageInfo::query_all()?,
network_interfaces: NetworkInfo::query_all()?,
battery: BatteryInfo::query().ok(),
thermal: ThermalInfo::query()?,
pci_devices: PCIDevice::query_all()?,
usb_devices: USBDevice::query_all()?,
power_profile: PowerProfile::query().ok(),
virtualization: VirtualizationInfo::detect()?,
})
}
pub fn cpu(&self) -> &CPUInfo {
&self.cpu
}
pub fn gpus(&self) -> &[GPUInfo] {
&self.gpus
}
pub fn npus(&self) -> &[NPUInfo] {
&self.npus
}
pub fn tpus(&self) -> &[TPUInfo] {
&self.tpus
}
pub fn arm_hardware(&self) -> Option<&ARMHardwareInfo> {
self.arm_hardware.as_ref()
}
pub fn fpgas(&self) -> &[FPGAInfo] {
&self.fpgas
}
pub fn memory(&self) -> &MemoryInfo {
&self.memory
}
pub fn storage_devices(&self) -> &[StorageInfo] {
&self.storage_devices
}
pub fn network_interfaces(&self) -> &[NetworkInfo] {
&self.network_interfaces
}
pub fn battery(&self) -> Option<&BatteryInfo> {
self.battery.as_ref()
}
pub fn thermal(&self) -> &ThermalInfo {
&self.thermal
}
pub fn pci_devices(&self) -> &[PCIDevice] {
&self.pci_devices
}
pub fn usb_devices(&self) -> &[USBDevice] {
&self.usb_devices
}
pub fn power_profile(&self) -> Option<&PowerProfile> {
self.power_profile.as_ref()
}
pub fn virtualization(&self) -> &VirtualizationInfo {
&self.virtualization
}
pub fn is_arm_system(&self) -> bool {
self.arm_hardware.is_some()
}
pub fn has_fpgas(&self) -> bool {
!self.fpgas.is_empty()
}
pub fn is_virtualized(&self) -> bool {
self.virtualization.is_virtualized()
}
pub fn is_containerized(&self) -> bool {
self.virtualization.is_containerized()
}
pub fn virtualization_performance_impact(&self) -> f64 {
self.virtualization.get_performance_factor()
}
pub fn accelerator_count(&self) -> usize {
self.npus.len() + self.tpus.len() + self.fpgas.len()
}
pub fn accelerator_summary(&self) -> HashMap<String, usize> {
let mut summary = HashMap::new();
if !self.npus.is_empty() {
summary.insert("NPUs".to_string(), self.npus.len());
}
if !self.tpus.is_empty() {
summary.insert("TPUs".to_string(), self.tpus.len());
}
if !self.fpgas.is_empty() {
summary.insert("FPGAs".to_string(), self.fpgas.len());
}
summary
}
pub fn to_json(&self) -> Result<String> {
serde_json::to_string_pretty(self).map_err(Into::into)
}
pub fn from_json(json: &str) -> Result<Self> {
serde_json::from_str(json).map_err(Into::into)
}
pub fn summary(&self) -> HardwareSummary {
HardwareSummary {
cpu_model: format!("{} {}", self.cpu.vendor(), self.cpu.model_name()),
cpu_cores: self.cpu.physical_cores(),
cpu_threads: self.cpu.logical_cores(),
total_memory_gb: self.memory.total_gb(),
primary_gpu: self.gpus.first().map(|gpu| {
format!(
"{} {} ({} GB)",
gpu.vendor(),
gpu.model_name(),
gpu.memory_gb()
)
}),
storage_total_gb: self
.storage_devices
.iter()
.map(|storage| storage.capacity_gb())
.sum(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HardwareSummary {
pub cpu_model: String,
pub cpu_cores: u32,
pub cpu_threads: u32,
pub total_memory_gb: f64,
pub primary_gpu: Option<String>,
pub storage_total_gb: f64,
}
impl std::fmt::Display for HardwareSummary {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "Hardware Summary:")?;
writeln!(
f,
" CPU: {} ({} cores, {} threads)",
self.cpu_model, self.cpu_cores, self.cpu_threads
)?;
writeln!(f, " Memory: {:.1} GB", self.total_memory_gb)?;
if let Some(gpu) = &self.primary_gpu {
writeln!(f, " Primary GPU: {gpu}")?;
}
writeln!(f, " Total Storage: {:.1} GB", self.storage_total_gb)?;
Ok(())
}
}