#[cfg(target_os = "linux")]
use crate::affinity::{cpu_count, for_each_online_cpu};
use crate::error::CpuAffinityError;
#[cfg(target_os = "linux")]
use std::{collections::HashSet, fs};
#[cfg(target_os = "linux")]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
struct PhysicalCore {
package_id: usize,
core_id: usize,
}
#[cfg(target_os = "linux")]
pub fn physical_core_count() -> Result<usize, CpuAffinityError> {
let mut seen_cores = HashSet::new();
for_each_online_cpu(|cpu| {
if let Some(core) = physical_core_for_cpu(cpu) {
seen_cores.insert(core);
}
})?;
if seen_cores.is_empty() {
cpu_count()
} else {
Ok(seen_cores.len())
}
}
#[cfg(not(target_os = "linux"))]
pub fn physical_core_count() -> Result<usize, CpuAffinityError> {
Err(CpuAffinityError::NotSupported)
}
#[cfg(target_os = "linux")]
fn physical_core_for_cpu(cpu: usize) -> Option<PhysicalCore> {
physical_core_from_ids(
read_topology_id(cpu, "physical_package_id"),
read_topology_id(cpu, "core_id"),
)
}
#[cfg(target_os = "linux")]
fn read_topology_id(cpu: usize, name: &str) -> Option<usize> {
let path = format!("/sys/devices/system/cpu/cpu{cpu}/topology/{name}");
fs::read_to_string(path).ok()?.trim().parse().ok()
}
#[cfg(target_os = "linux")]
fn physical_core_from_ids(
package_id: Option<usize>,
core_id: Option<usize>,
) -> Option<PhysicalCore> {
Some(PhysicalCore {
package_id: package_id.unwrap_or(0),
core_id: core_id?,
})
}
#[cfg(test)]
#[cfg(target_os = "linux")]
mod tests {
use super::{PhysicalCore, physical_core_from_ids};
use std::collections::HashSet;
#[test]
fn physical_core_requires_core_id() {
assert_eq!(physical_core_from_ids(Some(0), None), None);
}
#[test]
fn physical_core_defaults_missing_package_to_zero() {
assert_eq!(
physical_core_from_ids(None, Some(7)),
Some(PhysicalCore {
package_id: 0,
core_id: 7
})
);
}
#[test]
fn physical_core_key_includes_package_id() {
let mut cores = HashSet::new();
cores.insert(physical_core_from_ids(Some(0), Some(3)).unwrap());
cores.insert(physical_core_from_ids(Some(1), Some(3)).unwrap());
assert_eq!(cores.len(), 2);
}
}