#[cfg(doc)]
use crate::cpu::binding::CpuBindingFlags;
use crate::{
cpu::cpuset::CpuSet,
errors::{self, HybridError, RawHwlocError},
path::{self, PathError},
topology::Topology,
};
#[allow(unused)]
#[cfg(test)]
use similar_asserts::assert_eq;
use std::{ops::Deref, path::Path};
#[cfg(target_os = "linux")]
use libc::pid_t;
#[cfg(all(doc, not(target_os = "linux")))]
#[allow(non_camel_case_types)]
struct pid_t;
impl Topology {
#[allow(clippy::missing_errors_doc)]
#[doc(alias = "hwloc_linux_set_tid_cpubind")]
pub fn bind_tid_cpu(
&self,
tid: pid_t,
set: impl Deref<Target = CpuSet>,
) -> Result<(), RawHwlocError> {
fn polymorphized(self_: &Topology, tid: pid_t, set: &CpuSet) -> Result<(), RawHwlocError> {
errors::call_hwloc_zero_or_minus1("hwloc_linux_set_tid_cpubind", || unsafe {
hwlocality_sys::hwloc_linux_set_tid_cpubind(self_.as_ptr(), tid, set.as_ptr())
})
}
polymorphized(self, tid, &set)
}
#[allow(clippy::missing_errors_doc)]
#[doc(alias = "hwloc_linux_get_tid_cpubind")]
pub fn tid_cpu_binding(&self, tid: pid_t) -> Result<CpuSet, RawHwlocError> {
let mut set = CpuSet::new();
errors::call_hwloc_zero_or_minus1("hwloc_linux_get_tid_cpubind", || unsafe {
hwlocality_sys::hwloc_linux_get_tid_cpubind(self.as_ptr(), tid, set.as_mut_ptr())
})
.map(|()| set)
}
#[allow(clippy::missing_errors_doc)]
#[doc(alias = "hwloc_linux_get_tid_last_cpu_location")]
pub fn last_tid_cpu_location(&self, tid: pid_t) -> Result<CpuSet, RawHwlocError> {
let mut set = CpuSet::new();
errors::call_hwloc_zero_or_minus1("hwloc_linux_get_tid_last_cpu_location", || unsafe {
hwlocality_sys::hwloc_linux_get_tid_last_cpu_location(
self.as_ptr(),
tid,
set.as_mut_ptr(),
)
})
.map(|()| set)
}
#[cfg_attr(target_os = "linux", doc = "```rust")]
#[cfg_attr(not(target_os = "linux"), doc = "```rust,ignore")]
#[doc(alias = "hwloc_linux_read_path_as_cpumask")]
pub fn read_path_as_cpumask(
&self,
path: impl AsRef<Path>,
) -> Result<CpuSet, HybridError<PathError>> {
fn polymorphized(path: &Path) -> Result<CpuSet, HybridError<PathError>> {
let path = path::make_hwloc_path(path)?;
let mut set = CpuSet::new();
errors::call_hwloc_zero_or_minus1("hwloc_linux_read_path_as_cpumask", || unsafe {
hwlocality_sys::hwloc_linux_read_path_as_cpumask(path.borrow(), set.as_mut_ptr())
})
.map(|()| set)
.map_err(HybridError::Hwloc)
}
polymorphized(path.as_ref())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
cpu::binding::CpuBindingFlags, object::types::ObjectType, strategies::topology_related_set,
};
use proptest::prelude::*;
#[allow(unused)]
use similar_asserts::assert_eq;
#[test]
fn read_path_as_cpumask() {
let topology = Topology::test_instance();
let core_set = topology
.read_path_as_cpumask("/sys/devices/system/cpu/cpu0/topology/core_cpus")
.unwrap();
assert_eq!(
core_set,
topology
.objects_with_type(ObjectType::Core)
.next()
.unwrap()
.cpuset()
.unwrap()
);
}
#[test]
fn initial_tid_cpubind() {
let my_tid = unsafe { libc::gettid() };
let topology = Topology::test_instance();
let my_cpu_binding = topology
.process_cpu_binding(my_tid.try_into().unwrap(), CpuBindingFlags::THREAD)
.unwrap();
assert_eq!(topology.tid_cpu_binding(my_tid).unwrap(), my_cpu_binding);
let last_cpu_location = topology.last_tid_cpu_location(my_tid).unwrap();
assert_eq!(last_cpu_location.weight(), Some(1));
assert!(my_cpu_binding.includes(&last_cpu_location));
}
proptest! {
#[test]
fn bind_tid_cpu(
set in topology_related_set(Topology::allowed_cpuset)
) {
let my_tid = unsafe { libc::gettid() };
let topology = Topology::test_instance();
let initial = topology.tid_cpu_binding(my_tid).unwrap();
let result = topology.bind_tid_cpu(my_tid, &set);
if result.is_err() {
prop_assert!(!initial.includes(&set) || set.is_empty());
return Ok(());
}
let actual_binding = topology.tid_cpu_binding(my_tid).unwrap();
prop_assert!(
actual_binding == set
|| set.includes(&actual_binding),
"actual binding {actual_binding} doesn't match request {set}"
);
prop_assert!(set.includes(&topology.last_tid_cpu_location(my_tid).unwrap()));
topology.bind_tid_cpu(my_tid, &initial).unwrap();
}
}
}