#![warn(missing_docs, clippy::missing_docs_in_private_items)]
use std::sync::OnceLock;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum CpuTier {
Scalar,
Avx2,
Avx512,
Avx512Vnni,
Neon,
NeonDotprod,
NeonI8mm,
}
impl CpuTier {
pub fn label(self) -> &'static str {
match self {
CpuTier::Scalar => "scalar",
CpuTier::Avx2 => "avx2",
CpuTier::Avx512 => "avx512",
CpuTier::Avx512Vnni => "avx512+vnni",
CpuTier::Neon => "neon",
CpuTier::NeonDotprod => "neon+dotprod",
CpuTier::NeonI8mm => "neon+i8mm",
}
}
fn parse(s: &str) -> Option<CpuTier> {
match s.trim().to_ascii_lowercase().as_str() {
"scalar" | "none" | "off" => Some(CpuTier::Scalar),
#[cfg(target_arch = "x86_64")]
"avx2" => Some(CpuTier::Avx2),
#[cfg(target_arch = "x86_64")]
"avx512" => Some(CpuTier::Avx512),
#[cfg(target_arch = "x86_64")]
"vnni" | "avx512+vnni" | "avx512vnni" => Some(CpuTier::Avx512Vnni),
#[cfg(target_arch = "aarch64")]
"neon" => Some(CpuTier::Neon),
#[cfg(target_arch = "aarch64")]
"dotprod" | "neon+dotprod" | "neon,dotprod" => Some(CpuTier::NeonDotprod),
#[cfg(target_arch = "aarch64")]
"i8mm" | "neon+i8mm" | "neon,i8mm" => Some(CpuTier::NeonI8mm),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CpuFeatures {
pub tier: CpuTier,
pub avx2: bool,
pub fma: bool,
pub avx512f: bool,
pub avx512bw: bool,
pub avx512vl: bool,
pub avx512vnni: bool,
pub neon: bool,
pub dotprod: bool,
pub i8mm: bool,
pub fp16: bool,
}
impl CpuFeatures {
const NONE: CpuFeatures = CpuFeatures {
tier: CpuTier::Scalar,
avx2: false,
fma: false,
avx512f: false,
avx512bw: false,
avx512vl: false,
avx512vnni: false,
neon: false,
dotprod: false,
i8mm: false,
fp16: false,
};
fn active_flags(&self) -> Vec<&'static str> {
let mut flags: Vec<&str> = Vec::new();
for (on, name) in [
(self.avx2, "avx2"),
(self.fma, "fma"),
(self.avx512f, "avx512f"),
(self.avx512bw, "avx512bw"),
(self.avx512vl, "avx512vl"),
(self.avx512vnni, "avx512vnni"),
(self.neon, "neon"),
(self.dotprod, "dotprod"),
(self.i8mm, "i8mm"),
(self.fp16, "fp16"),
] {
if on {
flags.push(name);
}
}
flags
}
pub fn report(&self) -> String {
format!(
"cpu: tier={} [{}]",
self.tier.label(),
self.active_flags().join(" ")
)
}
pub fn descriptor(&self) -> String {
let flags = self.active_flags();
if flags.is_empty() {
self.tier.label().to_string()
} else {
flags.join(",")
}
}
pub fn ensure_supported(&self) -> Result<(), String> {
let _ = self;
Ok(())
}
}
pub fn detect() -> CpuFeatures {
#[cfg_attr(
not(any(target_arch = "x86_64", target_arch = "aarch64")),
allow(unused_mut)
)]
let mut f = CpuFeatures::NONE;
#[cfg(target_arch = "x86_64")]
{
f.avx2 = is_x86_feature_detected!("avx2");
f.fma = is_x86_feature_detected!("fma");
f.avx512f = is_x86_feature_detected!("avx512f");
f.avx512bw = is_x86_feature_detected!("avx512bw");
f.avx512vl = is_x86_feature_detected!("avx512vl");
f.avx512vnni = is_x86_feature_detected!("avx512vnni");
f.tier = if f.avx512f
&& f.avx512vl
&& f.avx512vnni
&& f.avx2
&& f.fma
&& cfg!(feature = "avx512")
{
CpuTier::Avx512Vnni
} else if f.avx512f && f.avx2 && f.fma && cfg!(feature = "avx512") {
CpuTier::Avx512
} else if f.avx2 && f.fma {
CpuTier::Avx2
} else {
CpuTier::Scalar
};
}
#[cfg(target_arch = "aarch64")]
{
f.neon = std::arch::is_aarch64_feature_detected!("neon");
f.dotprod = std::arch::is_aarch64_feature_detected!("dotprod");
f.i8mm = std::arch::is_aarch64_feature_detected!("i8mm");
f.fp16 = std::arch::is_aarch64_feature_detected!("fp16");
f.tier = if f.neon && f.dotprod && f.i8mm && f.fp16 {
CpuTier::NeonI8mm
} else if f.neon && f.dotprod {
CpuTier::NeonDotprod
} else if f.neon {
CpuTier::Neon
} else {
CpuTier::Scalar
};
}
apply_env_override(f)
}
fn apply_env_override(f: CpuFeatures) -> CpuFeatures {
match std::env::var("CERA_CPU_TIER") {
Ok(val) => with_tier_override(f, CpuTier::parse(&val)),
Err(_) => f,
}
}
fn with_tier_override(mut f: CpuFeatures, forced: Option<CpuTier>) -> CpuFeatures {
if let Some(t) = forced
&& t < f.tier
{
f.tier = t;
}
f
}
pub fn cpu_features() -> &'static CpuFeatures {
static FEATURES: OnceLock<CpuFeatures> = OnceLock::new();
FEATURES.get_or_init(detect)
}
pub fn cpu_tier() -> CpuTier {
cpu_features().tier
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CoreTopology {
pub perf_core_count: usize,
pub pin_cores: Vec<usize>,
pub fast_cores: usize,
pub core_weights: Vec<u32>,
}
impl CoreTopology {
pub fn report(&self) -> String {
let placement = if self.pin_cores.is_empty() {
"flat (no per-core placement, so capacity-aware sizing and \
pin-widening are both inert)"
.to_string()
} else {
match self.core_weights.iter().min() {
Some(&min) if min < WEIGHT_FULL => format!(
"tiered ({:.2}x fastest:slowest)",
f64::from(WEIGHT_FULL) / f64::from(min)
),
_ => "uniform (capacity-aware sizing is inert)".to_string(),
}
};
format!(
"cores: pinnable={} fast={} perf_pool={} placement={}",
self.pin_cores.len(),
self.fast_cores,
self.perf_core_count,
placement,
)
}
}
pub const WEIGHT_FULL: u32 = 256;
#[cfg(any(target_os = "linux", target_os = "android"))]
const MAX_CPUS: usize = 512;
#[cfg(any(target_os = "linux", target_os = "android"))]
const CAP_MID: u32 = 400;
pub fn core_topology() -> &'static CoreTopology {
static TOPOLOGY: OnceLock<CoreTopology> = OnceLock::new();
TOPOLOGY.get_or_init(detect_topology)
}
pub(crate) fn env_usize(name: &str) -> Option<usize> {
std::env::var(name)
.ok()
.and_then(|v| v.trim().parse::<usize>().ok())
.filter(|&n| n >= 1)
}
pub(crate) fn env_disabled(name: &str) -> bool {
std::env::var(name)
.map(|v| {
let v = v.trim();
["0", "false", "off"]
.iter()
.any(|d| v.eq_ignore_ascii_case(d))
})
.unwrap_or(false)
}
pub(crate) fn pinning_disabled() -> bool {
static OFF: OnceLock<bool> = OnceLock::new();
*OFF.get_or_init(|| env_disabled("CERA_PIN"))
}
pub fn performance_core_count() -> usize {
core_topology().perf_core_count
}
pub fn physical_core_count() -> Option<usize> {
static COUNT: OnceLock<Option<usize>> = OnceLock::new();
*COUNT.get_or_init(|| {
#[cfg(any(target_os = "linux", target_os = "android"))]
if let Some(n) = linux_physical_cores() {
return Some(n);
}
#[cfg(any(target_os = "macos", target_os = "ios"))]
if let Some(n) = macos_sysctl_usize(c"hw.perflevel0.physicalcpu") {
return Some(n);
}
None
})
}
#[cfg(any(target_os = "linux", target_os = "android"))]
fn linux_physical_cores() -> Option<usize> {
let sets = read_per_cpu_trimmed("topology/thread_siblings_list");
if sets.is_empty() {
return None;
}
let distinct: std::collections::HashSet<&str> = sets.iter().map(|(_, s)| s.as_str()).collect();
Some(distinct.len())
}
pub fn detect_topology() -> CoreTopology {
let forced = env_usize("CERA_THREADS");
let pinning_on = !pinning_disabled();
#[cfg(any(target_os = "linux", target_os = "android"))]
if let Some(topo) = detect_topology_sysfs() {
return apply_thread_override(topo, forced, pinning_on);
}
#[cfg(any(target_os = "macos", target_os = "ios"))]
if let Some(count) = macos_perf_core_count() {
return apply_thread_override(
CoreTopology {
perf_core_count: count,
pin_cores: Vec::new(),
fast_cores: 0,
core_weights: Vec::new(),
},
forced,
pinning_on,
);
}
let n = std::thread::available_parallelism()
.map(|p| p.get())
.unwrap_or(1);
apply_thread_override(
CoreTopology {
perf_core_count: n,
pin_cores: Vec::new(),
fast_cores: 0,
core_weights: Vec::new(),
},
forced,
pinning_on,
)
}
fn apply_thread_override(
mut topo: CoreTopology,
forced: Option<usize>,
pinning_on: bool,
) -> CoreTopology {
let Some(n) = forced else { return topo };
let n = if topo.pin_cores.is_empty() || !pinning_on {
n
} else {
let cap = topo.pin_cores.len();
if n > cap {
tracing::warn!(
"cera: CERA_THREADS={n} exceeds the {cap} pinnable cores on this host; \
clamping to {cap} (the surplus workers would run unpinned and contend \
with spinning ones)"
);
}
n.min(cap)
};
topo.perf_core_count = n;
topo.pin_cores.truncate(n);
topo.core_weights.truncate(topo.pin_cores.len());
topo.fast_cores = topo.fast_cores.min(topo.pin_cores.len());
topo
}
#[cfg_attr(
not(any(target_os = "linux", target_os = "android")),
allow(
dead_code,
reason = "only the sysfs detector calls it; tested on all hosts"
)
)]
fn normalize_core_weights(cores: &[(usize, u32)]) -> Vec<u32> {
let max_weight = u64::from(cores.iter().map(|&(_, w)| w).max().unwrap_or(0)).max(1);
cores
.iter()
.map(|&(_, w)| {
let scaled = u64::from(w) * u64::from(WEIGHT_FULL);
scaled.div_ceil(max_weight).clamp(1, u64::from(WEIGHT_FULL)) as u32
})
.collect()
}
#[cfg(any(target_os = "linux", target_os = "android"))]
fn detect_topology_sysfs() -> Option<CoreTopology> {
let caps = read_per_cpu_u32("cpu_capacity");
let mut cores: Vec<(usize, u32)>;
let perf_threshold: u32;
if !caps.is_empty() {
if caps.iter().all(|&(_, c)| c == caps[0].1) {
return None;
}
perf_threshold = CAP_MID;
cores = caps;
} else {
let freqs = read_per_cpu_u32("cpufreq/cpuinfo_max_freq");
let max = freqs.iter().map(|&(_, f)| f).max()?;
let cutoff = (max / 100) * 85;
if freqs.iter().all(|&(_, f)| f >= cutoff) {
return None;
}
perf_threshold = cutoff;
cores = freqs;
}
if cores.is_empty() {
return None;
}
let sibling_sets: std::collections::HashMap<usize, String> =
read_per_cpu_trimmed("topology/thread_siblings_list")
.into_iter()
.collect();
let mut seen_sets = std::collections::HashSet::new();
cores.retain(|&(cpu, _)| match sibling_sets.get(&cpu) {
Some(set) => seen_sets.insert(set.clone()),
None => true,
});
cores.sort_by(|a, b| b.1.cmp(&a.1).then(a.0.cmp(&b.0)));
let perf_core_count = cores
.iter()
.filter(|&&(_, w)| w >= perf_threshold)
.count()
.max(1);
let pin_cores: Vec<usize> = cores.iter().map(|&(i, _)| i).collect();
let fast_cores = perf_core_count;
let core_weights = normalize_core_weights(&cores);
Some(CoreTopology {
perf_core_count,
pin_cores,
fast_cores,
core_weights,
})
}
#[cfg(any(target_os = "linux", target_os = "android"))]
fn read_per_cpu_trimmed(file: &str) -> Vec<(usize, String)> {
let mut values = Vec::new();
for cpu in 0..MAX_CPUS {
let dir = format!("/sys/devices/system/cpu/cpu{cpu}");
if !std::path::Path::new(&dir).is_dir() {
break;
}
if let Ok(s) = std::fs::read_to_string(format!("{dir}/{file}")) {
values.push((cpu, s.trim().to_string()));
}
}
values
}
#[cfg(any(target_os = "linux", target_os = "android"))]
fn read_per_cpu_u32(file: &str) -> Vec<(usize, u32)> {
read_per_cpu_trimmed(file)
.into_iter()
.filter_map(|(cpu, s)| s.parse().ok().map(|v| (cpu, v)))
.collect()
}
#[cfg(any(target_os = "macos", target_os = "ios"))]
fn macos_perf_core_count() -> Option<usize> {
macos_sysctl_usize(c"hw.perflevel0.logicalcpu")
}
#[cfg(any(target_os = "macos", target_os = "ios"))]
fn macos_sysctl_usize(name: &std::ffi::CStr) -> Option<usize> {
if cfg!(miri) {
return None;
}
unsafe extern "C" {
fn sysctlbyname(
name: *const std::ffi::c_char,
oldp: *mut std::ffi::c_void,
oldlenp: *mut usize,
newp: *const std::ffi::c_void,
newlen: usize,
) -> i32;
}
let mut value: i32 = 0;
let mut size = std::mem::size_of::<i32>();
let ret = unsafe {
sysctlbyname(
name.as_ptr(),
&mut value as *mut _ as *mut std::ffi::c_void,
&mut size,
std::ptr::null(),
0,
)
};
(ret == 0 && value > 0).then_some(value as usize)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn topology_has_at_least_one_thread() {
let topo = detect_topology();
assert!(topo.perf_core_count >= 1);
assert!(topo.pin_cores.is_empty() || topo.pin_cores.len() >= topo.perf_core_count);
assert_eq!(core_topology().perf_core_count, performance_core_count());
}
#[test]
fn thread_override_sets_count_and_caps_pins() {
let base = CoreTopology {
perf_core_count: 3,
pin_cores: vec![7, 6, 5],
fast_cores: 3,
core_weights: vec![WEIGHT_FULL, WEIGHT_FULL, WEIGHT_FULL],
};
let two = apply_thread_override(base.clone(), Some(2), true);
assert_eq!(two.perf_core_count, 2);
assert_eq!(two.pin_cores, vec![7, 6]);
assert_eq!(apply_thread_override(base.clone(), None, true), base);
}
#[test]
fn thread_override_leaves_fast_cores_alone() {
let big_little = CoreTopology {
perf_core_count: 6,
pin_cores: vec![7, 6, 5, 4, 3, 2, 1, 0],
fast_cores: 6,
core_weights: vec![256, 206, 206, 206, 206, 206, 52, 52],
};
let wide = apply_thread_override(big_little.clone(), Some(8), true);
assert_eq!(wide.perf_core_count, 8);
assert_eq!(wide.fast_cores, 6, "widening leaked onto the E-cores");
assert_eq!(&wide.pin_cores[..wide.fast_cores], &[7, 6, 5, 4, 3, 2]);
let narrow = apply_thread_override(big_little, Some(3), true);
assert_eq!(narrow.fast_cores, 3);
assert!(narrow.fast_cores <= narrow.pin_cores.len());
}
#[test]
fn thread_override_clamps_to_pinnable_cores() {
let pinned = CoreTopology {
perf_core_count: 3,
pin_cores: vec![7, 6, 5],
fast_cores: 3,
core_weights: vec![WEIGHT_FULL, WEIGHT_FULL, WEIGHT_FULL],
};
let five = apply_thread_override(pinned, Some(5), true);
assert_eq!(five.perf_core_count, 3);
assert_eq!(five.pin_cores, vec![7, 6, 5]);
let unpinned = CoreTopology {
perf_core_count: 8,
pin_cores: Vec::new(),
fast_cores: 0,
core_weights: Vec::new(),
};
let wide = apply_thread_override(unpinned, Some(16), true);
assert_eq!(wide.perf_core_count, 16);
}
#[test]
fn core_weights_rescale_relative_to_the_fastest_core() {
let g5 = [(7, 1024u32), (6, 824), (5, 824), (1, 207), (0, 207)];
assert_eq!(
normalize_core_weights(&g5),
vec![256, 206, 206, 52, 52],
"weights are not relative to the prime core"
);
}
#[test]
fn core_weights_are_full_when_cores_are_equal() {
let homogeneous = [(0, 1024u32), (1, 1024), (2, 1024), (3, 1024)];
assert!(
normalize_core_weights(&homogeneous)
.iter()
.all(|&w| w == WEIGHT_FULL)
);
}
#[test]
fn core_weights_never_normalize_to_zero() {
let extreme = [(0, u32::MAX), (1, 1)];
assert_eq!(normalize_core_weights(&extreme), vec![256, 1]);
assert_eq!(normalize_core_weights(&[(0, 0), (1, 0)]), vec![1, 1]);
assert!(normalize_core_weights(&[]).is_empty());
}
#[test]
fn thread_override_keeps_weights_aligned_with_pins() {
let big_little = CoreTopology {
perf_core_count: 6,
pin_cores: vec![7, 6, 5, 4, 3, 2, 1, 0],
fast_cores: 6,
core_weights: vec![256, 206, 206, 206, 206, 206, 52, 52],
};
let narrow = apply_thread_override(big_little.clone(), Some(3), true);
assert_eq!(narrow.pin_cores.len(), narrow.core_weights.len());
assert_eq!(narrow.core_weights, vec![256, 206, 206]);
let wide = apply_thread_override(big_little, Some(16), true);
assert_eq!(wide.pin_cores.len(), wide.core_weights.len());
}
#[test]
fn thread_override_is_not_clamped_when_pinning_is_off() {
let big_little = CoreTopology {
perf_core_count: 6,
pin_cores: vec![7, 6, 5, 4, 3, 2, 1, 0],
fast_cores: 6,
core_weights: vec![256, 206, 206, 206, 206, 206, 52, 52],
};
let pinned = apply_thread_override(big_little.clone(), Some(16), true);
assert_eq!(pinned.perf_core_count, 8, "clamped to the pinnable cores");
let unpinned = apply_thread_override(big_little, Some(16), false);
assert_eq!(
unpinned.perf_core_count, 16,
"CERA_PIN=0 still clamped, so an oversubscription sweep is impossible"
);
assert_eq!(unpinned.pin_cores.len(), 8);
assert_eq!(unpinned.core_weights.len(), 8);
}
#[test]
fn tier_ordering_is_monotonic_per_arch() {
assert!(CpuTier::Scalar < CpuTier::Avx2);
assert!(CpuTier::Avx2 < CpuTier::Avx512);
assert!(CpuTier::Scalar < CpuTier::Neon);
assert!(CpuTier::Neon < CpuTier::NeonDotprod);
assert!(CpuTier::NeonDotprod < CpuTier::NeonI8mm);
}
#[test]
fn descriptor_is_compact_sorted_and_never_empty() {
assert_eq!(CpuFeatures::NONE.descriptor(), "scalar");
let neon = CpuFeatures {
tier: CpuTier::NeonI8mm,
neon: true,
dotprod: true,
i8mm: true,
..CpuFeatures::NONE
};
assert_eq!(neon.descriptor(), "neon,dotprod,i8mm");
let real = CpuFeatures { fp16: true, ..neon };
assert_eq!(real.descriptor(), "neon,dotprod,i8mm,fp16");
let m1 = CpuFeatures {
tier: CpuTier::NeonDotprod,
neon: true,
dotprod: true,
fp16: true,
..CpuFeatures::NONE
};
assert_eq!(m1.descriptor(), "neon,dotprod,fp16");
let x86 = CpuFeatures {
tier: CpuTier::Avx2,
avx2: true,
fma: true,
..CpuFeatures::NONE
};
assert_eq!(x86.descriptor(), "avx2,fma");
assert!(x86.report().contains("[avx2 fma]"));
}
#[test]
fn detect_is_stable_and_cached() {
assert_eq!(*cpu_features(), detect());
assert_eq!(cpu_features().tier, cpu_tier());
}
#[test]
fn detected_tier_matches_arch() {
let t = detect().tier;
#[cfg(target_arch = "x86_64")]
assert!(matches!(
t,
CpuTier::Scalar | CpuTier::Avx2 | CpuTier::Avx512 | CpuTier::Avx512Vnni
));
#[cfg(target_arch = "aarch64")]
assert!(matches!(
t,
CpuTier::Scalar | CpuTier::Neon | CpuTier::NeonDotprod | CpuTier::NeonI8mm
));
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
assert_eq!(t, CpuTier::Scalar);
}
#[test]
fn env_override_only_downgrades() {
let at = |t: CpuTier| CpuFeatures {
tier: t,
..CpuFeatures::NONE
};
assert_eq!(
with_tier_override(at(CpuTier::Avx2), Some(CpuTier::Scalar)).tier,
CpuTier::Scalar
);
assert_eq!(
with_tier_override(at(CpuTier::Avx2), Some(CpuTier::Avx512)).tier,
CpuTier::Avx2
);
assert_eq!(
with_tier_override(at(CpuTier::NeonDotprod), Some(CpuTier::NeonDotprod)).tier,
CpuTier::NeonDotprod
);
assert_eq!(
with_tier_override(at(CpuTier::Avx2), None).tier,
CpuTier::Avx2
);
}
#[test]
fn tier_label_roundtrips_through_parse() {
#[cfg(target_arch = "x86_64")]
let tiers = vec![
CpuTier::Scalar,
CpuTier::Avx2,
CpuTier::Avx512,
CpuTier::Avx512Vnni,
];
#[cfg(target_arch = "aarch64")]
let tiers = vec![
CpuTier::Scalar,
CpuTier::Neon,
CpuTier::NeonDotprod,
CpuTier::NeonI8mm,
];
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
let tiers = vec![CpuTier::Scalar];
for t in tiers {
assert_eq!(CpuTier::parse(t.label()), Some(t), "label {:?}", t.label());
}
}
#[test]
fn cross_arch_override_label_is_rejected() {
#[cfg(target_arch = "aarch64")]
{
assert_eq!(CpuTier::parse("avx2"), None);
assert_eq!(CpuTier::parse("avx512"), None);
}
#[cfg(target_arch = "x86_64")]
{
assert_eq!(CpuTier::parse("neon"), None);
assert_eq!(CpuTier::parse("i8mm"), None);
}
}
#[test]
fn topology_report_distinguishes_flat_from_tiered() {
let unknown = CoreTopology {
perf_core_count: 8,
pin_cores: Vec::new(),
fast_cores: 0,
core_weights: Vec::new(),
};
let r = unknown.report();
assert!(r.contains("placement=flat"), "{r}");
let homogeneous = CoreTopology {
perf_core_count: 4,
pin_cores: vec![0, 1, 2, 3],
fast_cores: 4,
core_weights: vec![WEIGHT_FULL; 4],
};
let r = homogeneous.report();
assert!(r.contains("placement=uniform"), "{r}");
let heterogeneous = CoreTopology {
perf_core_count: 6,
pin_cores: vec![0, 1, 2, 3, 4, 5, 6, 7],
fast_cores: 6,
core_weights: vec![WEIGHT_FULL, WEIGHT_FULL, 206, 206, 206, 206, 52, 52],
};
let r = heterogeneous.report();
assert!(r.contains("placement=tiered"), "{r}");
assert!(r.contains("4.92x"), "{r}");
assert!(r.contains("pinnable=8"), "{r}");
assert!(r.contains("fast=6"), "{r}");
}
#[test]
fn report_includes_tier_label() {
let r = cpu_features().report();
assert!(r.contains("tier="));
assert!(r.contains(cpu_tier().label()));
}
}