Skip to main content

aocl_utils/
threads.rs

1//! Thread-pinning helpers from AOCL-Utils.
2//!
3//! These are very thin wrappers around the AOCL routines that take a
4//! list of OS-level thread handles (`pthread_t` on Unix, `HANDLE` on
5//! Windows) and pin them to physical or logical cores. Most callers
6//! collect `pthread_t` / `HANDLE` values from their thread library
7//! (`std::thread::current().handle()`-style accessors via `os`-specific
8//! crates) before invoking these.
9//!
10//! The functions are `unsafe` because passing a thread handle that no
11//! longer refers to a live thread is undefined behavior on the AOCL
12//! side.
13
14use aocl_utils_sys as sys;
15
16/// OS-native thread handle.
17pub type ThreadHandle = sys::pthread_t;
18
19/// Pinning strategy for a list of thread handles.
20#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
21pub enum PinStrategy {
22    /// Pin each thread to a unique physical core (one thread per core,
23    /// preferring physical core 0, 1, 2, …).
24    Core,
25    /// Pin each thread to a unique logical processor (SMT thread).
26    Logical,
27    /// Spread threads across cores to maximize per-thread cache, mapping
28    /// each thread to a different L3 / NUMA region when possible.
29    Spread,
30}
31
32/// Pin the given thread handles using the chosen strategy.
33///
34/// # Safety
35///
36/// Each entry of `threads` must be a valid OS-level handle to a still-live
37/// thread. Passing a stale handle (e.g. for a thread that has exited or
38/// been detached) is undefined behavior. The slice's length must fit in
39/// a C `size_t`.
40pub unsafe fn pin_threads(strategy: PinStrategy, threads: &mut [ThreadHandle]) {
41    let n = threads.len();
42    let p = threads.as_mut_ptr();
43    match strategy {
44        PinStrategy::Core => unsafe { sys::au_pin_threads_core(p, n) },
45        PinStrategy::Logical => unsafe { sys::au_pin_threads_logical(p, n) },
46        PinStrategy::Spread => unsafe { sys::au_pin_threads_spread(p, n) },
47    }
48}
49
50/// Pin threads with a custom mapping: `affinity_vector[i]` is the logical
51/// processor index thread `i` should bind to.
52///
53/// # Safety
54///
55/// Same as [`pin_threads`]; in addition, the affinity values must
56/// reference logical processors that exist on the host.
57pub unsafe fn pin_threads_custom(threads: &mut [ThreadHandle], affinity_vector: &[i32]) {
58    let n = threads.len();
59    if n == 0 || affinity_vector.is_empty() {
60        return;
61    }
62    unsafe {
63        sys::au_pin_threads_custom(
64            threads.as_mut_ptr(),
65            n,
66            affinity_vector.as_ptr() as *mut std::os::raw::c_int,
67            affinity_vector.len(),
68        );
69    }
70}