use std::cell::UnsafeCell;
use std::sync::atomic::{AtomicBool, AtomicU64, AtomicUsize, Ordering};
use std::sync::{Arc, Mutex, OnceLock};
use std::thread::{self, JoinHandle};
#[cfg(not(miri))]
const SPIN_BEFORE_PARK: u32 = 100_000;
#[cfg(miri)]
const SPIN_BEFORE_PARK: u32 = 4;
#[cfg(not(miri))]
const DRAIN_SPIN_BEFORE_YIELD: u32 = 10_000;
#[cfg(miri)]
const DRAIN_SPIN_BEFORE_YIELD: u32 = 4;
const PIN_RETRY_BACKOFF: u32 = 1024;
#[derive(Clone, Copy)]
struct Job {
y_ptr: *mut f32,
n: usize,
chunk_rows: usize,
min_chunk_rows: usize,
total_rows: usize,
active: usize,
closure: *const (),
run: unsafe fn(closure: *const (), y_ptr: *mut f32, n: usize, start: usize, end: usize),
}
unsafe fn trampoline<F: Fn(usize, &mut [f32]) + Sync>(
closure: *const (),
y_ptr: *mut f32,
n: usize,
start: usize,
end: usize,
) {
let f = unsafe { &*(closure as *const F) };
for row in start..end {
let slice = unsafe { std::slice::from_raw_parts_mut(y_ptr.add(row * n), n) };
f(row, slice);
}
}
struct Shared {
active_barrier: bool,
state: AtomicU64,
next_row: AtomicUsize,
worker_weights: Vec<u32>,
pending: AtomicUsize,
shutdown: AtomicBool,
panicked: AtomicBool,
parked_count: AtomicUsize,
panic_payload: Mutex<Option<Box<dyn std::any::Any + Send>>>,
job: UnsafeCell<Option<Job>>,
}
const STEAL_CHUNKS_PER_WORKER: usize = 4;
const MIN_CHUNK_ROWS: usize = 16;
const GEMM_WORK_PER_WORKER_DEFAULT: usize = 48_000_000;
fn gemm_work_per_worker() -> usize {
static Q: OnceLock<usize> = OnceLock::new();
*Q.get_or_init(|| {
super::cpu_features::env_usize("CERA_GEMM_WORK_PER_WORKER")
.unwrap_or(GEMM_WORK_PER_WORKER_DEFAULT)
})
}
const ACTIVE_BITS: u64 = 16;
const ACTIVE_MASK: u64 = (1 << ACTIVE_BITS) - 1;
#[inline]
fn pack_state(epoch: u64, active: usize) -> u64 {
debug_assert!(
active as u64 <= ACTIVE_MASK,
"active {active} exceeds ACTIVE_MASK ({ACTIVE_MASK})"
);
(epoch << ACTIVE_BITS) | (active as u64 & ACTIVE_MASK)
}
#[inline]
fn state_epoch(state: u64) -> u64 {
state >> ACTIVE_BITS
}
#[inline]
fn state_active(state: u64) -> usize {
(state & ACTIVE_MASK) as usize
}
#[inline]
fn prefill_should_pin(fast_cores: usize, n: usize) -> bool {
fast_cores == 0 || n <= fast_cores
}
#[inline]
fn worker_chunk_rows(shared: &Shared, job: &Job, worker_id: usize) -> usize {
match shared.worker_weights.get(worker_id) {
Some(&w) if w < super::cpu_features::WEIGHT_FULL => {
let scaled = (job.chunk_rows as u64 * u64::from(w)
/ u64::from(super::cpu_features::WEIGHT_FULL)) as usize;
scaled.max(job.min_chunk_rows).max(1)
}
_ => job.chunk_rows,
}
}
#[inline]
fn steal_and_run(shared: &Shared, job: &Job, worker_id: usize) {
let chunk_rows = worker_chunk_rows(shared, job, worker_id);
debug_assert!(chunk_rows >= 1, "a zero-row claim would never terminate");
loop {
let start = shared.next_row.fetch_add(chunk_rows, Ordering::Relaxed);
if start >= job.total_rows {
break;
}
let end = (start + chunk_rows).min(job.total_rows);
unsafe { (job.run)(job.closure, job.y_ptr, job.n, start, end) };
}
}
unsafe impl Sync for Shared {}
unsafe impl Send for Shared {}
pub struct RowPool {
shared: Arc<Shared>,
workers: Vec<JoinHandle<()>>,
dispatch_lock: Mutex<()>,
caller_pin: Option<usize>,
num_threads: usize,
#[cfg(test)]
workers_pinned: bool,
}
pub mod stats {
use std::sync::atomic::{AtomicU64, Ordering};
pub(super) static FANOUT_DISPATCHES: AtomicU64 = AtomicU64::new(0);
pub(super) static SERIAL_FALLBACKS: AtomicU64 = AtomicU64::new(0);
pub(super) static FANOUT_MACS: AtomicU64 = AtomicU64::new(0);
pub(super) static SERIAL_MACS: AtomicU64 = AtomicU64::new(0);
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct PoolStats {
pub fanout_dispatches: u64,
pub serial_fallbacks: u64,
pub fanout_macs: u64,
pub serial_macs: u64,
}
impl PoolStats {
pub fn serial_mac_fraction(&self) -> f64 {
if self.fanout_macs == 0 {
return 0.0;
}
(self.serial_macs as f64 / self.fanout_macs as f64).clamp(0.0, 1.0)
}
pub fn since(&self, earlier: &PoolStats) -> PoolStats {
PoolStats {
fanout_dispatches: self
.fanout_dispatches
.saturating_sub(earlier.fanout_dispatches),
serial_fallbacks: self
.serial_fallbacks
.saturating_sub(earlier.serial_fallbacks),
fanout_macs: self.fanout_macs.saturating_sub(earlier.fanout_macs),
serial_macs: self.serial_macs.saturating_sub(earlier.serial_macs),
}
}
}
pub fn snapshot() -> PoolStats {
let serial_fallbacks = SERIAL_FALLBACKS.load(Ordering::Relaxed);
let serial_macs = SERIAL_MACS.load(Ordering::Relaxed);
let fanout_dispatches = FANOUT_DISPATCHES.load(Ordering::Relaxed);
let fanout_macs = FANOUT_MACS.load(Ordering::Relaxed);
PoolStats {
fanout_dispatches,
fanout_macs,
serial_fallbacks: serial_fallbacks.min(fanout_dispatches),
serial_macs: serial_macs.min(fanout_macs),
}
}
}
pub(crate) fn pinning_enabled() -> bool {
!super::cpu_features::pinning_disabled()
}
impl RowPool {
pub fn prefill() -> &'static RowPool {
static POOL: OnceLock<RowPool> = OnceLock::new();
POOL.get_or_init(|| {
let topo = super::cpu_features::core_topology();
let n = super::calibrate::prefill_thread_count(topo);
let widened = !prefill_should_pin(topo.fast_cores, n);
let (cores, weights, spread) = if widened {
(&[][..], &[][..], pinned_cores())
} else {
(pinned_cores(), pinned_core_weights(), &[][..])
};
RowPool::build(n, cores, weights, spread, true)
})
}
pub fn decode() -> &'static RowPool {
static POOL: OnceLock<RowPool> = OnceLock::new();
POOL.get_or_init(|| {
let topo = super::cpu_features::core_topology();
let n = super::calibrate::decode_thread_count(topo);
RowPool::build(n, pinned_cores(), pinned_core_weights(), &[], false)
})
}
fn build(
num_threads: usize,
pin_cores: &[usize],
core_weights: &[u32],
spread_mask: &'static [usize],
active_barrier: bool,
) -> RowPool {
let num_threads = num_threads.max(1).min(ACTIVE_MASK as usize);
let spin_limit = std::env::var("CERA_SPIN")
.ok()
.and_then(|v| v.trim().parse::<u32>().ok())
.unwrap_or(SPIN_BEFORE_PARK);
let worker_weights: Vec<u32> = core_weights.iter().take(num_threads).copied().collect();
let worker_weights = if worker_weights
.iter()
.any(|&w| w < super::cpu_features::WEIGHT_FULL)
{
worker_weights
} else {
Vec::new()
};
let shared = Arc::new(Shared {
active_barrier,
state: AtomicU64::new(0),
next_row: AtomicUsize::new(0),
worker_weights,
pending: AtomicUsize::new(0),
shutdown: AtomicBool::new(false),
panicked: AtomicBool::new(false),
parked_count: AtomicUsize::new(0),
panic_payload: Mutex::new(None),
job: UnsafeCell::new(None),
});
let mut workers = Vec::new();
for id in 1..num_threads {
let shared = Arc::clone(&shared);
let pin = pin_cores.get(id).copied();
match thread::Builder::new()
.name(format!("cera-rowpool-{id}"))
.spawn(move || worker_loop(shared, id, pin, spread_mask, spin_limit))
{
Ok(handle) => workers.push(handle),
Err(_) => break,
}
}
let num_threads = 1 + workers.len();
let caller_pin = pin_cores.first().copied();
RowPool {
shared,
workers,
dispatch_lock: Mutex::new(()),
caller_pin,
num_threads,
#[cfg(test)]
workers_pinned: !pin_cores.is_empty(),
}
}
pub fn num_threads(&self) -> usize {
self.num_threads
}
}
#[cfg(any(target_os = "macos", target_os = "ios"))]
pub fn set_macos_thread_qos_interactive() {
unsafe extern "C" {
fn pthread_set_qos_class_self_np(qos_class: u32, relative_priority: i32) -> i32;
}
const QOS_CLASS_USER_INTERACTIVE: u32 = 0x21;
unsafe {
pthread_set_qos_class_self_np(QOS_CLASS_USER_INTERACTIVE, 0);
}
}
impl RowPool {
fn pin_caller_once(&self) {
static CALLER_PIN_CLAIMED: AtomicBool = AtomicBool::new(false);
struct ClaimGuard;
impl Drop for ClaimGuard {
fn drop(&mut self) {
CALLER_PIN_CLAIMED.store(false, Ordering::Release);
}
}
struct CallerClaim {
guard: Option<ClaimGuard>,
retry_cooldown: u32,
}
thread_local! {
static CLAIM: std::cell::RefCell<CallerClaim> = const {
std::cell::RefCell::new(CallerClaim {
guard: None,
retry_cooldown: 0,
})
};
#[cfg(any(target_os = "macos", target_os = "ios"))]
static QOS_SET: std::cell::Cell<bool> = const { std::cell::Cell::new(false) };
}
#[cfg(any(target_os = "macos", target_os = "ios"))]
QOS_SET.with(|q| {
if !q.get() {
set_macos_thread_qos_interactive();
q.set(true);
}
});
let Some(core) = self.caller_pin else {
return;
};
CLAIM.with(|c| {
let mut claim = c.borrow_mut();
if claim.retry_cooldown > 0 {
claim.retry_cooldown -= 1;
return;
}
if claim.guard.is_some() {
let _ = pin_current_thread_to_core(core);
claim.retry_cooldown = PIN_RETRY_BACKOFF;
return;
}
if !CALLER_PIN_CLAIMED.load(Ordering::Relaxed)
&& CALLER_PIN_CLAIMED
.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
.is_ok()
{
if pin_current_thread_to_core(core) {
claim.guard = Some(ClaimGuard);
claim.retry_cooldown = PIN_RETRY_BACKOFF;
} else {
CALLER_PIN_CLAIMED.store(false, Ordering::Release);
claim.retry_cooldown = PIN_RETRY_BACKOFF;
}
}
});
}
pub fn dispatch_rows<F>(&self, y: &mut [f32], n: usize, min_rows: usize, f: F)
where
F: Fn(usize, &mut [f32]) + Sync,
{
self.dispatch_rows_chunked(y, n, min_rows, MIN_CHUNK_ROWS, f);
}
pub fn dispatch_rows_chunked<F>(
&self,
y: &mut [f32],
n: usize,
min_rows: usize,
min_chunk_rows: usize,
f: F,
) where
F: Fn(usize, &mut [f32]) + Sync,
{
self.dispatch_inner(y, n, min_rows, min_chunk_rows, 0, f);
}
pub fn dispatch_rows_work<F>(
&self,
y: &mut [f32],
n: usize,
min_rows: usize,
depth: usize,
f: F,
) where
F: Fn(usize, &mut [f32]) + Sync,
{
self.dispatch_inner(y, n, min_rows, MIN_CHUNK_ROWS, depth, f);
}
fn dispatch_inner<F>(
&self,
y: &mut [f32],
n: usize,
min_rows: usize,
min_chunk_rows: usize,
depth: usize,
f: F,
) where
F: Fn(usize, &mut [f32]) + Sync,
{
debug_assert!(n >= 1, "dispatch_inner: n must be ≥ 1");
if n == 0 || y.is_empty() {
return;
}
self.pin_caller_once();
let total_rows = y.len() / n;
let (body, tail) = y.split_at_mut(total_rows * n);
self.dispatch_body(body, n, total_rows, min_rows, min_chunk_rows, depth, &f);
if !tail.is_empty() {
f(total_rows, tail);
}
}
#[allow(clippy::too_many_arguments)] fn dispatch_body<F>(
&self,
y: &mut [f32],
n: usize,
total_rows: usize,
min_rows: usize,
min_chunk_rows: usize,
depth: usize,
f: &F,
) where
F: Fn(usize, &mut [f32]) + Sync,
{
if total_rows == 0 {
return;
}
let min_rows = min_rows.max(1);
let rows_per_worker = total_rows.div_ceil(self.num_threads).max(min_rows);
let mut active = total_rows.div_ceil(rows_per_worker).min(self.num_threads);
if depth != 0 {
let total_macs = total_rows.saturating_mul(n).saturating_mul(depth);
let work_cap = (total_macs / gemm_work_per_worker()).clamp(1, self.num_threads);
active = active.min(work_cap);
}
let wanted_fanout = active > 1;
let guard = if wanted_fanout {
match self.dispatch_lock.try_lock() {
Ok(g) => Some(g),
Err(std::sync::TryLockError::Poisoned(p)) => Some(p.into_inner()),
Err(std::sync::TryLockError::WouldBlock) => None,
}
} else {
None
};
if wanted_fanout {
let macs = (total_rows as u64)
.saturating_mul(n as u64)
.saturating_mul(depth.max(1) as u64);
stats::FANOUT_DISPATCHES.fetch_add(1, Ordering::Relaxed);
stats::FANOUT_MACS.fetch_add(macs, Ordering::Relaxed);
if guard.is_none() {
stats::SERIAL_FALLBACKS.fetch_add(1, Ordering::Relaxed);
stats::SERIAL_MACS.fetch_add(macs, Ordering::Relaxed);
}
}
let Some(_guard) = guard else {
for row in 0..total_rows {
f(row, &mut y[row * n..row * n + n]);
}
return;
};
let min_chunk_rows = min_chunk_rows.max(1);
let chunk_rows = total_rows
.div_ceil(active * STEAL_CHUNKS_PER_WORKER)
.max(min_chunk_rows);
let y_ptr = y.as_mut_ptr();
let closure_ptr = (f as *const F).cast::<()>();
let job = Job {
y_ptr,
n,
chunk_rows,
min_chunk_rows,
total_rows,
active,
closure: closure_ptr,
run: trampoline::<F>,
};
if self.shared.panicked.load(Ordering::Relaxed) {
drop(self.take_panic_payload());
}
unsafe {
*self.shared.job.get() = Some(job);
}
self.shared.next_row.store(0, Ordering::Relaxed);
if self.shared.active_barrier {
self.shared.pending.store(active - 1, Ordering::Release);
let next_epoch = state_epoch(self.shared.state.load(Ordering::Relaxed)) + 1;
self.shared
.state
.store(pack_state(next_epoch, active), Ordering::SeqCst);
if self.shared.parked_count.load(Ordering::SeqCst) > 0 {
for h in self.workers.iter().take(active - 1) {
h.thread().unpark();
}
}
} else {
self.shared
.pending
.store(self.num_threads - 1, Ordering::Release);
self.shared.state.fetch_add(1, Ordering::SeqCst);
if self.shared.parked_count.load(Ordering::SeqCst) > 0 {
for h in &self.workers {
h.thread().unpark();
}
}
}
{
let _drain = DrainGuard {
shared: &self.shared,
};
steal_and_run(&self.shared, &job, 0);
}
if self.shared.panicked.load(Ordering::Relaxed) {
match self.take_panic_payload() {
Some(payload) => std::panic::resume_unwind(payload),
None => panic!("cera RowPool: a row closure panicked on a worker thread"),
}
}
}
fn take_panic_payload(&self) -> Option<Box<dyn std::any::Any + Send>> {
self.shared.panicked.store(false, Ordering::Relaxed);
self.shared
.panic_payload
.lock()
.unwrap_or_else(|p| p.into_inner())
.take()
}
}
struct DrainGuard<'a> {
shared: &'a Shared,
}
impl Drop for DrainGuard<'_> {
fn drop(&mut self) {
let mut spins = 0u32;
while self.shared.pending.load(Ordering::Acquire) != 0 {
spins = spins.saturating_add(1);
if spins < DRAIN_SPIN_BEFORE_YIELD {
std::hint::spin_loop();
} else {
thread::yield_now();
}
}
}
}
struct ParkedGuard<'a> {
counter: &'a AtomicUsize,
}
impl<'a> ParkedGuard<'a> {
#[inline]
fn enter(counter: &'a AtomicUsize) -> Self {
counter.fetch_add(1, Ordering::SeqCst);
Self { counter }
}
}
impl Drop for ParkedGuard<'_> {
#[inline]
fn drop(&mut self) {
self.counter.fetch_sub(1, Ordering::SeqCst);
}
}
impl Drop for RowPool {
fn drop(&mut self) {
self.shared.shutdown.store(true, Ordering::Release);
self.shared
.state
.fetch_add(1 << ACTIVE_BITS, Ordering::Release);
for h in &self.workers {
h.thread().unpark();
}
for handle in self.workers.drain(..) {
let _ = handle.join();
}
}
}
fn worker_loop(
shared: Arc<Shared>,
worker_id: usize,
pin_core: Option<usize>,
spread_mask: &'static [usize],
spin_limit: u32,
) {
#[cfg(any(target_os = "macos", target_os = "ios"))]
{
thread_local! {
static WORKER_QOS_SET: std::cell::Cell<bool> = const { std::cell::Cell::new(false) };
}
WORKER_QOS_SET.with(|q| {
if !q.get() {
set_macos_thread_qos_interactive();
q.set(true);
}
});
}
if let Some(core) = pin_core {
let _ = pin_current_thread_to_core(core);
} else if !spread_mask.is_empty() {
let _ = set_current_thread_affinity(spread_mask);
}
let run_job = |shared: &Shared, job: &Job| {
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
steal_and_run(shared, job, worker_id);
}));
if let Err(payload) = result {
let mut slot = shared
.panic_payload
.lock()
.unwrap_or_else(|p| p.into_inner());
if slot.is_none() {
*slot = Some(payload);
drop(slot);
} else {
drop(slot);
std::mem::forget(payload);
}
shared.panicked.store(true, Ordering::Release);
}
};
let mut last_state = 0u64;
loop {
let mut spins = 0u32;
let mut parked = false;
let state;
loop {
if shared.shutdown.load(Ordering::Acquire) {
return;
}
let st = shared.state.load(Ordering::Acquire);
if st != last_state {
last_state = st;
state = st;
break;
}
spins = spins.saturating_add(1);
if spins < spin_limit {
std::hint::spin_loop();
} else {
let _guard = ParkedGuard::enter(&shared.parked_count);
if shared.state.load(Ordering::SeqCst) != last_state
|| shared.shutdown.load(Ordering::SeqCst)
{
continue;
}
thread::park();
parked = true;
}
}
if shared.shutdown.load(Ordering::Acquire) {
return;
}
if parked {
if let Some(core) = pin_core {
let _ = pin_current_thread_to_core(core);
} else if !spread_mask.is_empty() {
let _ = set_current_thread_affinity(spread_mask);
}
}
if shared.active_barrier {
if worker_id >= state_active(state) {
continue;
}
if let Some(job) = unsafe { *shared.job.get() } {
run_job(&shared, &job);
}
shared.pending.fetch_sub(1, Ordering::Release);
} else {
let job = match unsafe { *shared.job.get() } {
Some(job) => job,
None => continue,
};
if worker_id < job.active {
run_job(&shared, &job);
}
shared.pending.fetch_sub(1, Ordering::Release);
}
}
}
#[cfg(any(target_os = "linux", target_os = "android"))]
pub(crate) fn pin_current_thread_to_core(core: usize) -> bool {
set_current_thread_affinity(&[core])
}
#[cfg(not(any(target_os = "linux", target_os = "android")))]
pub(crate) fn pin_current_thread_to_core(_core: usize) -> bool {
false
}
pub(crate) fn pinned_cores() -> &'static [usize] {
if pinning_enabled() {
&super::cpu_features::core_topology().pin_cores
} else {
&[]
}
}
pub(crate) fn pinned_core_weights() -> &'static [u32] {
if pinning_enabled() {
&super::cpu_features::core_topology().core_weights
} else {
&[]
}
}
pub(crate) fn perf_pinned_cores() -> &'static [usize] {
let cores = pinned_cores();
let fast = super::cpu_features::core_topology().fast_cores;
&cores[..fast.min(cores.len())]
}
#[cfg(any(target_os = "linux", target_os = "android"))]
pub(crate) fn set_current_thread_affinity(cores: &[usize]) -> bool {
if cores.is_empty() {
return false;
}
let capacity = std::mem::size_of::<libc::cpu_set_t>() * 8;
unsafe {
let mut set: libc::cpu_set_t = std::mem::zeroed();
let mut any = false;
for &core in cores {
if core < capacity {
libc::CPU_SET(core, &mut set);
any = true;
}
}
any && libc::sched_setaffinity(0, std::mem::size_of::<libc::cpu_set_t>(), &set) == 0
}
}
#[cfg(not(any(target_os = "linux", target_os = "android")))]
pub(crate) fn set_current_thread_affinity(_cores: &[usize]) -> bool {
false
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn dispatch_matches_serial_across_shapes_and_threads() {
for &active_barrier in &[true, false] {
for &num_threads in &[1usize, 2, 4, 7] {
let pool = RowPool::build(num_threads, &[], &[], &[], active_barrier);
for &n in &[1usize, 3, 8] {
for &total_rows in &[0usize, 1, 5, 256, 1000] {
let len = total_rows * n;
let mut got = vec![0.0f32; len];
let mut want = vec![0.0f32; len];
let fill = |row: usize, slice: &mut [f32]| {
for (k, v) in slice.iter_mut().enumerate() {
*v = (row * 100 + k) as f32;
}
};
pool.dispatch_rows(&mut got, n, 64, fill);
for row in 0..total_rows {
fill(row, &mut want[row * n..row * n + n]);
}
assert_eq!(
got, want,
"mismatch: barrier={active_barrier} threads={num_threads} n={n} rows={total_rows}"
);
}
}
}
}
}
#[test]
fn every_row_written_exactly_once() {
let pool = RowPool::build(4, &[], &[], &[], true);
let total_rows = 10_000usize;
let mut counts = vec![0.0f32; total_rows];
pool.dispatch_rows(&mut counts, 1, 1, |_row, slice| {
slice[0] += 1.0;
});
assert!(counts.iter().all(|&c| c == 1.0));
}
#[test]
fn weighted_workers_still_partition_rows_exactly_once() {
for weights in [
vec![256u32, 206, 206, 52, 52],
vec![256, 128, 64, 32],
vec![256, 1, 256, 1],
] {
for &active_barrier in &[true, false] {
let pool = RowPool::build(weights.len(), &[], &weights, &[], active_barrier);
for &total_rows in &[1usize, 7, 256, 4_096, 10_000, 65_537] {
let mut counts = vec![0.0f32; total_rows];
pool.dispatch_rows(&mut counts, 1, 1, |_row, slice| {
slice[0] += 1.0;
});
assert!(
counts.iter().all(|&c| c == 1.0),
"rows lost or written twice: weights={weights:?} \
barrier={active_barrier} rows={total_rows}"
);
}
}
}
}
#[test]
fn chunk_scales_in_proportion_to_weight() {
let full = super::super::cpu_features::WEIGHT_FULL;
let shared = Shared {
active_barrier: true,
state: AtomicU64::new(0),
next_row: AtomicUsize::new(0),
worker_weights: vec![full, 206, 52],
pending: AtomicUsize::new(0),
shutdown: AtomicBool::new(false),
panicked: AtomicBool::new(false),
parked_count: AtomicUsize::new(0),
panic_payload: Mutex::new(None),
job: UnsafeCell::new(None),
};
let job = Job {
y_ptr: std::ptr::null_mut(),
n: 1,
chunk_rows: 500,
min_chunk_rows: 1,
total_rows: 1 << 20,
active: 3,
closure: std::ptr::null(),
run: trampoline::<fn(usize, &mut [f32])>,
};
assert_eq!(
worker_chunk_rows(&shared, &job, 0),
500,
"prime core scaled"
);
assert_eq!(worker_chunk_rows(&shared, &job, 1), 402, "A725 scale wrong");
assert_eq!(worker_chunk_rows(&shared, &job, 2), 101, "A520 scale wrong");
}
#[test]
fn weight_scaling_floors_at_one_row() {
let shared = Shared {
active_barrier: true,
state: AtomicU64::new(0),
next_row: AtomicUsize::new(0),
worker_weights: vec![super::super::cpu_features::WEIGHT_FULL, 1],
pending: AtomicUsize::new(0),
shutdown: AtomicBool::new(false),
panicked: AtomicBool::new(false),
parked_count: AtomicUsize::new(0),
panic_payload: Mutex::new(None),
job: UnsafeCell::new(None),
};
let job = Job {
y_ptr: std::ptr::null_mut(),
n: 1,
chunk_rows: 4,
min_chunk_rows: 0,
total_rows: 1024,
active: 2,
closure: std::ptr::null(),
run: trampoline::<fn(usize, &mut [f32])>,
};
assert_eq!(worker_chunk_rows(&shared, &job, 0), 4);
assert_eq!(worker_chunk_rows(&shared, &job, 1), 1);
assert_eq!(worker_chunk_rows(&shared, &job, 7), 4);
let floored = Job {
chunk_rows: 256,
min_chunk_rows: 128,
..job
};
assert_eq!(worker_chunk_rows(&shared, &floored, 0), 256);
assert_eq!(
worker_chunk_rows(&shared, &floored, 1),
128,
"weighting scaled past the dispatcher's floor"
);
}
#[test]
fn uniform_weights_are_dropped_at_build() {
let full = super::super::cpu_features::WEIGHT_FULL;
let uniform = RowPool::build(4, &[], &[full, full, full, full], &[], true);
assert!(uniform.shared.worker_weights.is_empty());
let spread = RowPool::build(4, &[], &[full, full, full, 52], &[], true);
assert_eq!(spread.shared.worker_weights.len(), 4);
let narrow = RowPool::build(2, &[], &[full, 52, 52, 52], &[], true);
assert_eq!(narrow.shared.worker_weights, vec![full, 52]);
}
#[test]
fn shipping_pools_carry_the_detected_weights() {
let expected = pinned_core_weights();
let pools: Vec<&RowPool> = [RowPool::prefill(), RowPool::decode()]
.into_iter()
.filter(|p| p.workers_pinned || pinned_core_weights().is_empty())
.collect();
for pool in pools {
let got = &pool.shared.worker_weights;
if got.is_empty() {
assert!(
expected.is_empty()
|| expected
.iter()
.take(pool.num_threads())
.all(|&w| w == super::super::cpu_features::WEIGHT_FULL),
"pool dropped weights that would have scaled a worker down: {expected:?}"
);
} else {
assert_eq!(
got.len(),
expected.len().min(pool.num_threads()),
"pool weights are not one per worker"
);
assert_eq!(
got[..],
expected[..got.len()],
"pool weights do not match the detected topology"
);
}
}
}
#[test]
fn prefill_drops_pinning_only_once_wider_than_the_fast_cores() {
let widened = |fast: usize, n: usize| !prefill_should_pin(fast, n);
assert!(!widened(6, 6), "default width must keep pinning");
assert!(
!widened(6, 4),
"narrower than the fast set must keep pinning"
);
assert!(
widened(6, 7),
"one worker past the fast set already reaches an E-core"
);
assert!(widened(6, 8), "CERA_THREADS=8 must drop pinning");
assert!(
!widened(0, 32),
"policy fired on a host with no fast-core split"
);
}
#[test]
fn repeated_dispatches_reuse_workers() {
let pool = RowPool::build(4, &[], &[], &[], true);
let mut y = vec![0.0f32; 2048];
for iter in 0..50 {
pool.dispatch_rows(&mut y, 1, 1, |row, slice| {
slice[0] = (row + iter) as f32;
});
for (row, &v) in y.iter().enumerate() {
assert_eq!(v, (row + iter) as f32);
}
}
}
#[test]
fn varying_active_across_dispatches_is_correct() {
for &active_barrier in &[true, false] {
for &num_threads in &[2usize, 4, 8] {
let pool = RowPool::build(num_threads, &[], &[], &[], active_barrier);
for iter in 0..60usize {
let total_rows = if iter % 2 == 0 { 1 } else { 2048 };
let mut y = vec![0.0f32; total_rows];
pool.dispatch_rows(&mut y, 1, 1, |row, slice| slice[0] = (row + iter) as f32);
for (row, &v) in y.iter().enumerate() {
assert_eq!(
v,
(row + iter) as f32,
"barrier={active_barrier} threads={num_threads} iter={iter} row={row}"
);
}
}
}
}
}
#[test]
fn dispatch_rows_work_matches_serial() {
let pool = RowPool::build(8, &[], &[], &[], true);
for &depth in &[0usize, 1, 4096, 1_000_000] {
for &total_rows in &[0usize, 1, 3, 64, 500] {
let n = 4;
let mut got = vec![0.0f32; total_rows * n];
let mut want = vec![0.0f32; total_rows * n];
let fill = |row: usize, slice: &mut [f32]| {
for (k, v) in slice.iter_mut().enumerate() {
*v = (row * 7 + k) as f32;
}
};
pool.dispatch_rows_work(&mut got, n, 1, depth, fill);
for row in 0..total_rows {
fill(row, &mut want[row * n..row * n + n]);
}
assert_eq!(got, want, "depth={depth} rows={total_rows}");
}
}
}
#[test]
fn single_thread_pool_runs_serially() {
let pool = RowPool::build(1, &[], &[], &[], true);
assert_eq!(pool.num_threads(), 1);
let mut y = vec![0.0f32; 100];
pool.dispatch_rows(&mut y, 1, 1, |row, slice| slice[0] = row as f32);
assert!(y.iter().enumerate().all(|(i, &v)| v == i as f32));
}
#[test]
fn trailing_partial_row_matches_serial_chunks() {
let pool = RowPool::build(4, &[], &[], &[], true);
let n = 8usize;
let len = 8 * 300 + 5; let mut got = vec![0.0f32; len];
let fill = |row: usize, slice: &mut [f32]| {
for (k, v) in slice.iter_mut().enumerate() {
*v = (row * 1000 + k) as f32 + 1.0;
}
};
pool.dispatch_rows(&mut got, n, 1, fill);
let mut want = vec![0.0f32; len];
for (j, row) in want.chunks_mut(n).enumerate() {
fill(j, row);
}
assert_eq!(got, want);
}
#[test]
fn concurrent_dispatchers_are_safe() {
let pool = RowPool::build(4, &[], &[], &[], true);
for _ in 0..20 {
let mut a = vec![0.0f32; 4096];
let mut b = vec![0.0f32; 4096];
thread::scope(|s| {
let pool = &pool;
s.spawn(|| pool.dispatch_rows(&mut a, 1, 1, |row, s| s[0] = row as f32 + 1.0));
pool.dispatch_rows(&mut b, 1, 1, |row, s| s[0] = row as f32 + 2.0);
});
assert!(a.iter().enumerate().all(|(i, &v)| v == i as f32 + 1.0));
assert!(b.iter().enumerate().all(|(i, &v)| v == i as f32 + 2.0));
}
}
#[test]
fn fanout_counters_track_dispatches_and_stay_coherent() {
let before = stats::snapshot();
let pool = RowPool::build(4, &[], &[], &[], true);
for _ in 0..20 {
let mut a = vec![0.0f32; 4096];
let mut b = vec![0.0f32; 4096];
thread::scope(|s| {
let pool = &pool;
s.spawn(|| pool.dispatch_rows(&mut a, 1, 1, |row, s| s[0] = row as f32 + 1.0));
pool.dispatch_rows(&mut b, 1, 1, |row, s| s[0] = row as f32 + 2.0);
});
}
let delta = stats::snapshot().since(&before);
assert!(
delta.fanout_dispatches >= 40,
"40 multi-worker dispatches counted as {}",
delta.fanout_dispatches
);
let live = stats::snapshot();
assert!(
live.serial_fallbacks <= live.fanout_dispatches,
"serial {} > fanout {}",
live.serial_fallbacks,
live.fanout_dispatches
);
assert!(live.serial_macs <= live.fanout_macs);
let f = live.serial_mac_fraction();
assert!((0.0..=1.0).contains(&f), "fraction {f} outside 0.0..=1.0");
}
#[test]
fn worker_panic_propagates_and_pool_survives() {
let pool = RowPool::build(4, &[], &[], &[], true);
let mut y = vec![0.0f32; 4096];
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
pool.dispatch_rows(&mut y, 1, 1, |row, slice| {
if row == 2048 {
panic!("boom");
}
slice[0] = row as f32;
});
}));
let payload = result.expect_err("closure panic must propagate to the caller");
let msg: &str = payload
.downcast_ref::<&str>()
.copied()
.or_else(|| payload.downcast_ref::<String>().map(String::as_str))
.expect("payload must be the original panic message");
assert_eq!(msg, "boom");
let mut z = vec![0.0f32; 4096];
pool.dispatch_rows(&mut z, 1, 1, |row, slice| slice[0] = row as f32);
assert!(z.iter().enumerate().all(|(i, &v)| v == i as f32));
}
}