use std::io;
use crate::processor_set::ProcessorSet;
use crate::walk::{self, GroupAffinity, Record};
const LTP_PC_SMT: u8 = 0x1;
fn to_processor_set(masks: &[GroupAffinity]) -> ProcessorSet {
let mut set = ProcessorSet::empty();
for m in masks {
set = set.union(&ProcessorSet::from_group_mask(m.group, m.mask));
}
set
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct CoreRelation {
pub simultaneous_multithreading: bool,
pub efficiency_class: u8,
pub processors: ProcessorSet,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PackageRelation {
pub processors: ProcessorSet,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))]
#[non_exhaustive]
pub enum CacheKind {
Unified,
Instruction,
Data,
Trace,
Other(i32),
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct CacheRelation {
pub level: u8,
pub associativity: u8,
pub line_size: u16,
pub cache_size: u32,
pub cache_type: CacheKind,
pub processors: ProcessorSet,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct NumaNodeRelation {
pub node_number: u32,
pub processors: ProcessorSet,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct GroupRelation {
pub group: u16,
pub maximum_processor_count: u8,
pub active_processor_count: u8,
pub active_processors: ProcessorSet,
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct Relations {
pub cores: Vec<CoreRelation>,
pub packages: Vec<PackageRelation>,
pub dies: Vec<PackageRelation>,
pub modules: Vec<PackageRelation>,
pub caches: Vec<CacheRelation>,
pub numa_nodes: Vec<NumaNodeRelation>,
pub groups: Vec<GroupRelation>,
pub anomalies: Vec<crate::EnumerationAnomaly>,
}
fn core_from(body: walk::ProcessorBody) -> CoreRelation {
CoreRelation {
simultaneous_multithreading: body.flags & LTP_PC_SMT != 0,
efficiency_class: body.efficiency_class,
processors: to_processor_set(&body.group_masks),
}
}
fn package_from(body: walk::ProcessorBody) -> PackageRelation {
PackageRelation {
processors: to_processor_set(&body.group_masks),
}
}
fn cache_from(body: walk::CacheBody) -> CacheRelation {
CacheRelation {
level: body.level,
associativity: body.associativity,
line_size: body.line_size,
cache_size: body.cache_size,
cache_type: walk::cache_kind_from_raw(body.cache_type),
processors: to_processor_set(&body.group_masks),
}
}
fn numa_from(body: walk::NumaNodeBody) -> NumaNodeRelation {
NumaNodeRelation {
node_number: body.node_number,
processors: to_processor_set(&body.group_masks),
}
}
fn groups_from(body: walk::GroupBody) -> Vec<GroupRelation> {
body.group_info
.into_iter()
.enumerate()
.map(|(index, info)| GroupRelation {
group: index as u16,
maximum_processor_count: info.maximum_processor_count,
active_processor_count: info.active_processor_count,
active_processors: ProcessorSet::from_group_mask(
index as u16,
info.active_processor_mask,
),
})
.collect()
}
pub fn discover() -> io::Result<Relations> {
let mut relations = Relations::default();
let (walk_records, walk_anomalies) = walk::enumerate()?;
for record in walk_records {
match record {
Record::ProcessorCore(body) => relations.cores.push(core_from(body)),
Record::ProcessorPackage(body) => relations.packages.push(package_from(body)),
Record::ProcessorDie(body) => relations.dies.push(package_from(body)),
Record::ProcessorModule(body) => relations.modules.push(package_from(body)),
Record::Cache(body) => relations.caches.push(cache_from(body)),
Record::NumaNode(body) => relations.numa_nodes.push(numa_from(body)),
Record::Group(body) => relations.groups.extend(groups_from(body)),
Record::Unknown(_) => {}
}
}
relations.anomalies = walk_anomalies;
Ok(relations)
}
#[cfg(test)]
mod tests;