Expand description
The single seam every CPU parallel region in this crate goes through.
There used to be about fifty spellings of “run this over rows in
parallel” scattered through crate::weight_matrix alone, each one
an inline rayon iterator chain. That is the shape this repo has been
burned by before: many copies of one decision, with nothing making
them agree. Routing them all through the handful of functions below
means the choice of how work is scheduled is made in one place.
Which is exactly what issue #27 needs, because it wants that choice
changed: rayon forks and joins per operation, per layer, per token,
and llama.cpp instead hands work to a pool that is already awake.
Backend::Spin is that pool (crate::cpu_pool).
§The switch
Which of the two runs is decided per operation, from its size, by
the one predicate in policy: backend. FERROX_CPU_POOL pins
it either way (spin / rayon) and is an A/B override, not the
decision. See policy::SPIN_MIN_OP_MACS for the crossover and what
is and is not measured about it.
Every helper below asks backend and none of them decides
anything itself, which is what stops the two arms of that choice from
drifting apart across thirty call sites.
§min_len, and where MIN_TASK_MACS went
Every helper takes a min_len. On the rayon arm it is passed
straight to with_min_len, which is what the call sites did by hand
before, so the fork-join path’s task decomposition is bit-for-bit
what it was.
On the spin arm it is ignored. MIN_TASK_MACS existed to stop
rayon splitting a matvec into tasks too small to pay for their own
fork-join; when a region costs a cache-line transfer instead of a
futex there is nothing to pay for, so the spin arm chunks purely by
pool width (task_count) the way ggml_compute_forward_mul_mat
does. That is the deletion issue #27 asks for, and it is a deletion
rather than a retune: no MAC threshold is consulted on this path at
all. It survives on the rayon arm because the rayon arm still runs
every operation below the crossover, and removing it there re-opens
the measured 13-16x small-model regression documented on
crate::weight_matrix::WeightMatrix::min_rows_per_task.
Re-exports§
pub use policy::backend;pub use policy::macs_per_row;pub use policy::with_op_work;
Modules§
- policy
- Which CPU scheduler one operation’s parallel regions run on, and the work quantity that decides it.
Enums§
- Backend
- Which scheduler CPU parallel regions use.
Functions§
- chunks_
mut - Run
f(chunk_index, &mut chunk)overdatasplit into runs ofchunk_len, the shape rayon spellspar_chunks_mut(chunk_len). - chunks_
mut2 chunks_mutover two slices of the same length at once, the shape rayon spellsa.par_chunks_mut(k).zip(b.par_chunks_mut(k)).- chunks_
mut2_ by chunks_mut2with a chunk length per slice:ain runs oflen_a,bin runs oflen_b, the SAME number of chunks (a gated delta-net’s per-headS x Sstate beside its per-headSoutput).- chunks_
mut_ init chunks_mutwith a per-task scratch value.- cold_
regions - Parallel regions this thread has opened without being a rayon worker.
- indices
- Run
f(index)for everyindexin0..n. - indices_
init indiceswith a per-task scratch value, the shape rayon spellsfor_each_init. OneSis created per task, not per index.- items_
mut - Run
f(index, &mut item)overdata, the shape rayon spellspar_iter_mut().with_min_len(..).enumerate(). - join2
- Two independent pieces of work.
- join3
- Three independent pieces of work; see
join2. - num_
threads - Worker count of the active backend.
- on_
workers - Run
fon a rayon worker, so every parallel region it opens takes rayon’s IN-WORKER path instead of its cold-submission path. - task_
count - How many tasks the spin arm splits
n_itemsinto.