use crate::{AffinityMask, CacheInfo, CoreKind, CpuFeatures, L3Domain, Lp, Result, Vendor};
#[must_use]
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct CpuInfo {
pub lps: Vec<Lp>,
pub core_count: u16,
pub socket_count: u8,
pub numa_node_count: u8,
pub kind_core_counts: [u16; CoreKind::COUNT],
pub l3_domains: Vec<L3Domain>,
pub l1d: [CacheInfo; CoreKind::COUNT],
pub l1i: [CacheInfo; CoreKind::COUNT],
pub l2: [CacheInfo; CoreKind::COUNT],
pub vendor: Vendor,
pub model_name: String,
pub features: CpuFeatures,
}
impl CpuInfo {
#[must_use = "detecting topology has a cost; keep and reuse the returned CpuInfo"]
pub fn detect() -> Result<Self> {
#[cfg(target_os = "linux")]
{
crate::platform::linux::cpu::detect_cpu_info()
}
#[cfg(target_os = "macos")]
{
crate::platform::macos::cpu::detect_cpu_info()
}
#[cfg(target_os = "windows")]
{
crate::platform::windows::cpu::detect_cpu_info()
}
#[cfg(not(any(target_os = "windows", target_os = "linux", target_os = "macos")))]
{
Err(crate::Error::Unsupported(
"CPU information detection is not supported on this platform.".to_string(),
))
}
}
pub fn num_physical_cores(&self) -> usize {
self.core_count as usize
}
pub fn num_logical_cores(&self) -> usize {
self.lps.len()
}
pub fn num_performance_cores(&self) -> usize {
self.kind_core_counts[CoreKind::Performance.index()] as usize
}
pub fn num_efficiency_cores(&self) -> usize {
self.kind_core_counts[CoreKind::Efficiency.index()] as usize
}
pub fn num_lp_efficiency_cores(&self) -> usize {
self.kind_core_counts[CoreKind::LpEfficiency.index()] as usize
}
pub fn is_hybrid(&self) -> bool {
let kinds_present = [
CoreKind::Performance,
CoreKind::Efficiency,
CoreKind::LpEfficiency,
]
.iter()
.filter(|k| self.kind_core_counts[k.index()] > 0)
.count();
kinds_present > 1
}
pub fn logical_processor_ids(&self) -> Vec<usize> {
self.lps.iter().map(|lp| lp.os_id as usize).collect()
}
pub fn all_cores_mask(&self) -> AffinityMask {
self.mask_where(|_| true)
}
pub fn kind_mask(&self, kind: CoreKind) -> AffinityMask {
self.mask_where(|lp| lp.kind == kind)
}
pub fn performance_core_mask(&self) -> AffinityMask {
self.kind_mask(CoreKind::Performance)
}
pub fn efficiency_core_mask(&self) -> AffinityMask {
self.kind_mask(CoreKind::Efficiency)
}
pub fn lp_efficiency_core_mask(&self) -> AffinityMask {
self.kind_mask(CoreKind::LpEfficiency)
}
pub fn primary_thread_mask(&self) -> AffinityMask {
self.mask_where(|lp| lp.smt_index == 0)
}
pub fn l3_domain_mask(&self, domain: u8) -> AffinityMask {
self.l3_domains
.get(domain as usize)
.map(|d| d.mask)
.unwrap_or_else(AffinityMask::empty)
}
pub fn numa_node_mask(&self, node: u8) -> AffinityMask {
self.mask_where(|lp| lp.numa_node == node)
}
fn mask_where(&self, pred: impl Fn(&Lp) -> bool) -> AffinityMask {
let mut mask = AffinityMask::empty();
for lp in self.lps.iter().filter(|lp| pred(lp)) {
mask.add(lp.os_id as usize);
}
mask
}
}