use std::collections::BTreeSet;
#[derive(Clone, Debug, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum MemPolicy {
#[default]
Default,
Bind(BTreeSet<usize>),
Preferred(usize),
Interleave(BTreeSet<usize>),
Local,
PreferredMany(BTreeSet<usize>),
WeightedInterleave(BTreeSet<usize>),
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[serde(transparent)]
pub struct MpolFlags(u32);
impl MpolFlags {
pub const NONE: Self = Self(0);
pub const STATIC_NODES: Self = Self(1 << 15);
pub const RELATIVE_NODES: Self = Self(1 << 14);
pub const NUMA_BALANCING: Self = Self(1 << 13);
#[cfg(test)]
pub(crate) const fn from_bits_for_test(bits: u32) -> Self {
Self(bits)
}
pub const fn union(self, other: Self) -> Self {
Self(self.0 | other.0)
}
pub const fn bits(self) -> u32 {
self.0
}
pub const fn contains(self, other: Self) -> bool {
(self.0 & other.0) == other.0
}
}
impl std::ops::BitOr for MpolFlags {
type Output = Self;
fn bitor(self, rhs: Self) -> Self {
self.union(rhs)
}
}
impl MemPolicy {
pub fn bind(nodes: impl IntoIterator<Item = usize>) -> Self {
MemPolicy::Bind(nodes.into_iter().collect())
}
pub const fn preferred(node: usize) -> Self {
MemPolicy::Preferred(node)
}
pub fn interleave(nodes: impl IntoIterator<Item = usize>) -> Self {
MemPolicy::Interleave(nodes.into_iter().collect())
}
pub fn preferred_many(nodes: impl IntoIterator<Item = usize>) -> Self {
MemPolicy::PreferredMany(nodes.into_iter().collect())
}
pub fn weighted_interleave(nodes: impl IntoIterator<Item = usize>) -> Self {
MemPolicy::WeightedInterleave(nodes.into_iter().collect())
}
pub fn node_set(&self) -> BTreeSet<usize> {
match self {
MemPolicy::Default | MemPolicy::Local => BTreeSet::new(),
MemPolicy::Bind(nodes)
| MemPolicy::Interleave(nodes)
| MemPolicy::PreferredMany(nodes)
| MemPolicy::WeightedInterleave(nodes) => nodes.clone(),
MemPolicy::Preferred(node) => [*node].into_iter().collect(),
}
}
pub fn validate(&self) -> std::result::Result<(), String> {
match self {
MemPolicy::Default | MemPolicy::Local => Ok(()),
MemPolicy::Preferred(_) => Ok(()),
MemPolicy::Bind(nodes) if nodes.is_empty() => Err(
"Bind policy requires at least one NUMA node — \
use `MemPolicy::bind([node, ...])` with one or more node IDs, \
or `MemPolicy::Default` / `MemPolicy::Local` for non-bound placement"
.into(),
),
MemPolicy::Interleave(nodes) if nodes.is_empty() => Err(
"Interleave policy requires at least one NUMA node — \
use `MemPolicy::interleave([node, ...])` with one or more node IDs, \
or `MemPolicy::Default` for unrestricted placement"
.into(),
),
MemPolicy::PreferredMany(nodes) if nodes.is_empty() => Err(
"PreferredMany policy requires at least one NUMA node — \
use `MemPolicy::preferred_many([node, ...])` with one or more node IDs, \
or `MemPolicy::Preferred(node)` / `MemPolicy::Default` / `MemPolicy::Local`"
.into(),
),
MemPolicy::WeightedInterleave(nodes) if nodes.is_empty() => Err(
"WeightedInterleave policy requires at least one NUMA node — \
use `MemPolicy::weighted_interleave([node, ...])` with one or more node IDs, \
or `MemPolicy::interleave([node, ...])` / `MemPolicy::Default` for unweighted placement"
.into(),
),
_ => Ok(()),
}
}
}