use crate::error::BackendResult;
use crate::{Device, DeviceFeature, DeviceInfo};
use torsh_core::device::DeviceType;
#[cfg(not(feature = "std"))]
use alloc::string::String;
#[derive(Debug, Clone)]
pub struct CpuDevice {
id: usize,
num_cores: usize,
}
impl CpuDevice {
pub fn new(id: usize, num_cores: usize) -> BackendResult<Self> {
Ok(Self { id, num_cores })
}
pub fn id(&self) -> usize {
self.id
}
pub fn num_cores(&self) -> usize {
self.num_cores
}
pub fn to_device(&self) -> Device {
let info = DeviceInfo {
vendor: Self::get_cpu_vendor(),
driver_version: "N/A".to_string(),
total_memory: Self::get_total_memory(),
available_memory: Self::get_available_memory(),
compute_units: self.num_cores,
max_work_group_size: usize::MAX,
max_work_group_dimensions: vec![usize::MAX, 1, 1],
clock_frequency_mhz: 3000, memory_bandwidth_gbps: 50.0, peak_gflops: self.num_cores as f32 * 10.0, features: vec![
DeviceFeature::DoublePrecision,
DeviceFeature::UnifiedMemory,
DeviceFeature::AtomicOperations,
DeviceFeature::Profiling,
DeviceFeature::ConcurrentExecution,
DeviceFeature::AsyncMemory,
DeviceFeature::FastMath,
],
properties: vec![
("num_cores".to_string(), self.num_cores.to_string()),
("architecture".to_string(), Self::get_cpu_architecture()),
],
};
Device::new(
self.id,
DeviceType::Cpu,
format!("CPU ({} cores)", self.num_cores),
info,
)
}
fn get_total_memory() -> usize {
#[cfg(feature = "cpu")]
{
use sysinfo::System;
let mut sys = System::new_all();
sys.refresh_memory();
return sys.total_memory() as usize;
}
#[cfg(not(feature = "cpu"))]
{
8 * 1024 * 1024 * 1024 }
}
fn get_available_memory() -> usize {
#[cfg(feature = "cpu")]
{
use sysinfo::System;
let mut sys = System::new_all();
sys.refresh_memory();
return sys.available_memory() as usize;
}
#[cfg(not(feature = "cpu"))]
{
Self::get_total_memory() * 8 / 10
}
}
fn get_cpu_vendor() -> String {
#[cfg(target_arch = "x86_64")]
{
if let Some(info) = raw_cpuid::CpuId::new().get_vendor_info() {
return info.as_str().to_string();
}
}
#[cfg(target_arch = "aarch64")]
{
return "ARM".to_string();
}
#[allow(unreachable_code)]
"Unknown".to_string()
}
fn get_cpu_architecture() -> String {
#[cfg(target_arch = "x86_64")]
{
"x86_64".to_string()
}
#[cfg(target_arch = "aarch64")]
{
"aarch64".to_string()
}
#[cfg(target_arch = "arm")]
{
"arm".to_string()
}
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64", target_arch = "arm")))]
{
env!("TARGET").to_string()
}
}
}
impl From<CpuDevice> for Device {
fn from(cpu_device: CpuDevice) -> Self {
cpu_device.to_device()
}
}
impl From<&CpuDevice> for Device {
fn from(cpu_device: &CpuDevice) -> Self {
cpu_device.to_device()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_cpu_device_creation() {
let device = CpuDevice::new(0, 8).expect("Cpu Device should succeed");
assert_eq!(device.id(), 0);
assert_eq!(device.num_cores(), 8);
let device_info = device.to_device();
assert_eq!(device_info.device_type(), DeviceType::Cpu);
assert!(device_info.info().total_memory > 0);
}
#[test]
fn test_cpu_device_conversion() {
let cpu_device = CpuDevice::new(0, 4).expect("Cpu Device should succeed");
let device: Device = cpu_device.clone().into();
assert_eq!(device.device_type(), DeviceType::Cpu);
assert_eq!(device.id(), 0);
assert_eq!(device.info().compute_units, 4);
}
}