#![deny(warnings)]
#[derive(Debug, Clone, Copy)]
pub struct CpuInfo {
pub l1_cache_size: usize,
pub l2_cache_size: usize,
pub l3_cache_size: usize,
pub num_cpus: usize,
}
impl CpuInfo {
#[cfg(target_os = "linux")]
pub fn try_new() -> Result<CpuInfo, ()> {
use libc::sysconf;
unsafe {
let l1_cache_size = sysconf(libc::_SC_LEVEL1_DCACHE_SIZE);
if l1_cache_size <= 0 {
return Err(());
}
let l2_cache_size = sysconf(libc::_SC_LEVEL2_CACHE_SIZE);
if l2_cache_size <= 0 {
return Err(());
}
let l3_cache_size = sysconf(libc::_SC_LEVEL3_CACHE_SIZE);
if l3_cache_size <= 0 {
return Err(());
}
let num_cpus = sysconf(libc::_SC_NPROCESSORS_CONF);
if num_cpus <= 0 {
return Err(());
}
Ok(CpuInfo {
l1_cache_size: l1_cache_size as usize,
l2_cache_size: l2_cache_size as usize,
l3_cache_size: l3_cache_size as usize,
num_cpus: num_cpus as usize,
})
}
}
#[cfg(target_os = "macos")]
pub fn try_new() -> Result<CpuInfo, ()> {
use std::{mem, ptr};
use libc::{c_int, c_void, sysconf, sysctl};
unsafe {
let mut l1_cache_size: c_int = 0;
let mut l2_cache_size: c_int = 0;
let mut l3_cache_size: c_int = 0;
let mut size = mem::size_of::<c_int>();
const NAMELEN: libc::c_uint = 2;
let mut name = [libc::CTL_HW, libc::HW_L1DCACHESIZE];
if sysctl(
name.as_mut_ptr(),
NAMELEN,
&mut l1_cache_size as *mut c_int as *mut c_void,
&mut size,
ptr::null_mut(),
0,
) != 0
{
return Err(());
}
name[1] = libc::HW_L2CACHESIZE;
if sysctl(
name.as_mut_ptr(),
NAMELEN,
&mut l2_cache_size as *mut c_int as *mut c_void,
&mut size,
ptr::null_mut(),
0,
) != 0
{
return Err(());
}
name[1] = libc::HW_L3CACHESIZE;
if sysctl(
name.as_mut_ptr(),
NAMELEN,
&mut l3_cache_size as *mut c_int as *mut c_void,
&mut size,
ptr::null_mut(),
0,
) != 0
{
return Err(());
}
if l1_cache_size <= 0 || l2_cache_size <= 0 || l3_cache_size <= 0 {
return Err(());
}
let num_cpus = sysconf(libc::_SC_NPROCESSORS_CONF);
if num_cpus <= 0 {
return Err(());
}
Ok(CpuInfo {
l1_cache_size: l1_cache_size as usize,
l2_cache_size: l2_cache_size as usize,
l3_cache_size: l3_cache_size as usize,
num_cpus: num_cpus as usize,
})
}
}
#[cfg(target_os = "windows")]
pub fn try_new() -> Result<CpuInfo, ()> {
use std::{mem, ptr};
use winapi::shared::minwindef::{FALSE, TRUE};
use winapi::shared::winerror::ERROR_INSUFFICIENT_BUFFER;
use winapi::um::errhandlingapi::GetLastError;
use winapi::um::sysinfoapi::GetLogicalProcessorInformation;
use winapi::um::winnt::{
CacheData, RelationCache, RelationProcessorCore, SYSTEM_LOGICAL_PROCESSOR_INFORMATION,
};
unsafe {
let mut buffer = Vec::new();
let mut req_bytes = 0;
let struct_size = mem::size_of::<SYSTEM_LOGICAL_PROCESSOR_INFORMATION>();
if TRUE == GetLogicalProcessorInformation(ptr::null_mut(), &mut req_bytes) {
return Err(());
}
if GetLastError() == ERROR_INSUFFICIENT_BUFFER {
buffer.reserve(req_bytes as usize / struct_size);
buffer.set_len(req_bytes as usize / struct_size);
} else {
return Err(());
}
if FALSE == GetLogicalProcessorInformation(buffer.as_mut_ptr(), &mut req_bytes) {
return Err(());
}
let mut l1_cache_size = 0;
let mut l2_cache_size = 0;
let mut l3_cache_size = 0;
let mut num_cpus = 0;
for info in buffer {
if info.Relationship == RelationCache {
let cache = info.u.Cache();
match cache.Level {
1 => {
if cache.Type == CacheData {
l1_cache_size = cache.Size
}
}
2 => l2_cache_size = cache.Size,
3 => l3_cache_size = cache.Size,
_ => {
return Err(());
}
}
} else if info.Relationship == RelationProcessorCore {
num_cpus += 1;
}
}
if l1_cache_size == 0
|| l2_cache_size == 0
|| l3_cache_size == 0
|| num_cpus == 0 {
return Err(());
}
Ok(CpuInfo {
l1_cache_size: l1_cache_size as usize,
l2_cache_size: l2_cache_size as usize,
l3_cache_size: l3_cache_size as usize,
num_cpus,
})
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_create_cpu_info() {
let _info = CpuInfo::try_new().unwrap();
}
}