|
Clustering
C++20 header-only: DBSCAN, HDBSCAN, k-means.
|
Thin compile-time-templated wrapper around the underlying OwnedPool. More...
#include <clustering/math/thread.h>
Public Member Functions | |
| std::size_t | workerCount () const noexcept |
Number of worker threads available, or 1 in serial mode. | |
| bool | shouldParallelize (std::size_t totalWork, std::size_t minChunk, std::size_t minTasksPerWorker=2) const noexcept |
Decide whether totalWork warrants parallel dispatch. | |
| bool | shouldParallelizeWork (std::size_t totalOps, std::size_t minOpsPerWorker=std::size_t{1}<< 15) const noexcept |
Decide whether totalOps warrants parallel dispatch, based on work volume. | |
| std::size_t | stealBlocks (std::size_t n, std::size_t minRowsPerBlock=256) const noexcept |
Block count for a fan-out over n rows that lets work-stealing balance heterogeneous cores. | |
| template<class HintsT = citor::HintsDefaults, class FnA, class FnB> | |
| void | forkJoin2 (FnA &&a, FnB &&b) const |
| Run two independent tasks as a fork-join pair. | |
| template<class HintsT = citor::HintsDefaults, class Body> | |
| void | parallelForBlocks (std::size_t first, std::size_t last, std::size_t numBlocks, Body body) |
Run body in parallel over [first, last) partitioned into numBlocks blocks. | |
| template<class HintsT = citor::HintsDefaults, class Body> | |
| void | parallelForExactBlocks (std::size_t first, std::size_t last, std::size_t numBlocks, Body body) |
Run body in parallel with exactly numBlocks contiguous ranges. | |
| template<class HintsT = citor::HintsDefaults, class Body> | |
| void | parallelForExactBlocksWithSlot (std::size_t first, std::size_t last, std::size_t numBlocks, Body body) |
| Slot-aware variant of parallelForExactBlocks. | |
| template<class HintsT = citor::HintsDefaults, class Body> | |
| void | parallelForChunks (std::size_t numChunks, Body body) |
Run body once per chunk over [0, numChunks) in parallel. | |
| template<class HintsT = citor::HintsDefaults, class T, class Map, class Combine> | |
| T | parallelReduce (std::size_t first, std::size_t last, T init, Map map, Combine combine) |
| Reduce [first, last) with the backend's reduction primitive. | |
| template<class HintsT = citor::HintsDefaults, class Phase> | |
| void | parallelRunPlex (std::size_t nPhases, std::size_t n, Phase phaseFn) |
Run phaseFn for nPhases persistent-worker phases over [0, n). | |
| template<class HintsT = citor::HintsDefaults, class T, class BodyFn, class PrefixFn> | |
| T | parallelScan (std::size_t n, T identity, BodyFn body, PrefixFn prefix) |
| Two-pass exclusive-prefix scan over [0, n). | |
| template<class HintsT = citor::HintsDefaults, class T, class PrefixFn> | |
| T | inclusiveScan (std::span< const T > in, std::span< T > out, T identity, PrefixFn prefix) |
Buffer-to-buffer inclusive prefix scan of in into out. | |
| template<class HintsT = citor::HintsDefaults, class Phase, class PrePhase> | |
| void | parallelRunPlex (std::size_t nPhases, std::size_t n, Phase phaseFn, PrePhase prePhaseFn, citor::CancellationToken tok=citor::CancellationToken{}) |
| Pre-phase form of parallelRunPlex with cooperative cancellation. | |
Static Public Member Functions | |
| static std::size_t | workerIndex () noexcept |
| Stable index of the calling worker thread within the owning pool. | |
Public Attributes | |
| OwnedPool * | pool = nullptr |
Underlying pool, or nullptr to force serial execution. | |
Thin compile-time-templated wrapper around the underlying OwnedPool.
Carries an optional pool pointer plus the helpers math kernels need to decide whether a given workload is worth fanning out. A null pool is the explicit serial mode – shouldParallelize then always reports false and the kernel runs on the calling thread without touching any pool machinery.
The dispatch API methods (parallelForBlocks, parallelForChunks, parallelRunPlex) are templated on HintsT and forward through to citor::parallelFor<HintsT>(...) (or citor::ThreadPool::runPlex<HintsT> for the persistent-worker form). Each call monomorphizes into the same code a direct citor::parallelFor<HintsT> call would produce, with no runtime branching on hint fields.
workerIndex returns 0 outside any pool task. Callers that rely on per-worker scratch isolation must invoke it from inside a pool task body or pass Pool{nullptr} deliberately.
|
inline |
Run two independent tasks as a fork-join pair.
Serial mode (no pool attached) runs a then b inline on the calling thread. With a pool attached the pair dispatches through the backend's fork-join path, which supports nested calls from inside worker bodies; recursive divide-and-conquer callers fan out by invoking this again from their own task bodies. Synchronous: returns after both tasks complete, with their writes visible to the caller.
|
inlinenodiscard |
Buffer-to-buffer inclusive prefix scan of in into out.
Forwards to citor::ThreadPool::inclusiveScan, a single-pass decoupled-lookback scan with per-cluster lookback chains on multi-CCD parts: it both work-steals and weights its prefix chains by cluster, so a slower CCD does not gate the whole scan the way the block-per-worker Blelloch body does. Aliasing (in.data() == out.data()) is safe. A null pool runs the scan serially on the calling thread.
| HintsT | Hint type whose static-constexpr members drive compile-time policy. |
| in | Input span. |
| out | Output span; same length as in. |
| identity | Monoid identity for prefix. |
| prefix | Associative binary combiner. |
|
inline |
Run body in parallel over [first, last) partitioned into numBlocks blocks.
The body is invoked once per block as body(blockFirst, blockAfterLast). When pool is unset the call runs the entire range inline on the calling thread. Synchronous: the call returns only after every block has completed. HintsT is a citor hint type whose static-constexpr members drive compile-time policy on the citor backend; on the BS backend it is accepted for API uniformity and ignored.
| HintsT | Hint type whose static-constexpr members drive compile-time policy. |
| Body | Callable invocable as Body(std::size_t lo, std::size_t hi). |
| first | Inclusive lower bound of the iteration range. |
| last | Exclusive upper bound of the iteration range. |
| numBlocks | Requested block count; 0 selects the backend's default partition. |
| body | Callable invoked once per block. |
|
inline |
Run body once per chunk over [0, numChunks) in parallel.
The body is invoked as body(chunkIdx) with a single integer chunk index. Used by the symmetric-tile threshold path where work per chunk is heavily unbalanced (chunk 0 does the full triangle, the last chunk only the diagonal band) so each chunk maps to one task and the pool steals across them.
| HintsT | Hint type whose static-constexpr members drive compile-time policy. |
| Body | Callable invocable as Body(std::size_t chunkIdx). |
| numChunks | Total number of chunks to dispatch. |
| body | Callable invoked once per chunk. |
|
inline |
Run body in parallel with exactly numBlocks contiguous ranges.
Each block s receives [first + (last-first)*s/numBlocks, first +
(last-first)*(s+1)/numBlocks) as its (lo, hi) argument. The partition is identical across backends, so callers that need to map a starting lo back to the originating block index can do so deterministically (see kmeans::detail::BlockPartition for the matching decoder).
| HintsT | Hint type whose static-constexpr members drive compile-time policy. |
| Body | Callable invocable as Body(std::size_t lo, std::size_t hi). |
| first | Inclusive lower bound of the iteration range. |
| last | Exclusive upper bound of the iteration range. |
| numBlocks | Number of contiguous blocks; must be at least 1. |
| body | Callable invoked once per block. |
|
inline |
Slot-aware variant of parallelForExactBlocks.
Same partition semantics as parallelForExactBlocks but the body receives the originating slot index as a third argument. Use this when the body needs to slot into per-block scratch (one slab per block) without reverse-engineering the slot from the lo argument.
| HintsT | Hint type whose static-constexpr members drive compile-time policy. |
| Body | Callable invocable as Body(std::size_t lo, std::size_t hi, std::size_t slot). |
| first | Inclusive lower bound of the iteration range. |
| last | Exclusive upper bound of the iteration range. |
| numBlocks | Number of contiguous blocks; must be at least 1. |
| body | Callable invoked once per block with the block's slot index. |
|
inlinenodiscard |
Reduce [first, last) with the backend's reduction primitive.
On the citor backend this forwards to ThreadPool::parallelReduce<HintsT>, preserving citor's chunk-id tree and determinism policy. On the BS backend the same surface is emulated with one partial per worker-count slot, then folded by the producer in slot order.
| HintsT | citor reduction hint type, e.g. citor::HintsDefaults. |
| T | Reduction value type. |
| Map | Callable invocable as T(std::size_t lo, std::size_t hi). |
| Combine | Callable invocable as T(T a, T b). |
| first | Inclusive lower bound of the iteration range. |
| last | Exclusive upper bound of the iteration range. |
| init | Identity value. |
| map | Per-block mapper. |
| combine | Producer-side combiner. |
|
inline |
Run phaseFn for nPhases persistent-worker phases over [0, n).
Maps to citor::ThreadPool::runPlex<HintsT> on the citor backend, which keeps background workers spin-resident between phases (no per-phase futex round-trip). On the BS backend the form is emulated with a per-phase submit_blocks loop – the work is functionally equivalent but pays a per-phase submit/wait round-trip because BS lacks a persistent-plex primitive.
The body signature matches citor's: phaseFn(phaseIdx, slot, lo, hi, tlsArena). tlsArena is always nullptr on the BS path; callers that need per-slot scratch should derive it from slot themselves.
| HintsT | Hint type whose static-constexpr members drive compile-time policy. |
| Phase | Callable invocable as Phase(std::size_t phaseIdx, std::uint32_t slot, std::size_t lo, std::size_t hi, void* tlsArena). |
| nPhases | Number of phases to run; 0 is a no-op. |
| n | Row-range upper bound; partitioned per-slot as [n*slot/P, n*(slot+1)/P). |
| phaseFn | Callable invoked once per (phase, slot) pair. |
|
inline |
Pre-phase form of parallelRunPlex with cooperative cancellation.
A stopped tok exits the plex at the next phase boundary; the default sentinel never stops. Stop it from prePhaseFn to end the plex early – note the phase the hook precedes still fires once before the producer observes the flag.
|
inline |
Two-pass exclusive-prefix scan over [0, n).
Forwards to citor::ThreadPool::parallelScan<HintsT>: pass 1 invokes body once per slot with initial = @p identity to compute the chunk's partial; the producer then runs an O(slots) reduce via prefix; pass 2 re-invokes body with initial set to the chunk's exclusive prefix so the body can finish writing its slice. Returns the inclusive accumulator at the right edge.
On the BS backend the form is emulated with one parallelForExactBlocksWithSlot for the first pass, a serial prefix walk on the producer, and a second parallelForExactBlocksWithSlot for the offset add. Output is functionally equivalent; the serialization between passes is identical to citor's.
| HintsT | Hint type whose static-constexpr members drive compile-time policy. |
| T | Reduction value type. |
| BodyFn | Callable: T(chunkId, lo, hi, initial, out). out is unused on the BS path (always nullptr) and the citor path (the body owns the destination buffer captured by reference); kept in the signature so citor's CPO surface monomorphizes identically. |
| PrefixFn | Callable: T(T a, T b) cross-chunk reduce. |
| n | Range length. |
| identity | Identity value seeded into pass 1's body and returned for empty ranges. |
| body | Per-chunk body invoked twice (once per pass). |
| prefix | Cross-chunk binary combiner. |
|
inlinenodiscardnoexcept |
Decide whether totalWork warrants parallel dispatch.
Returns true only when a pool is attached and the work splits into at least workerCount() * minTasksPerWorker chunks of size minChunk. Guards against minChunk == 0 by reporting false rather than dividing by zero.
| totalWork | Total number of work units (e.g. matrix elements, rows). |
| minChunk | Minimum chunk size that amortizes per-task overhead. |
| minTasksPerWorker | Minimum chunks per worker required to bother fanning out. |
true when parallel dispatch should yield speedup, false otherwise.
|
inlinenodiscardnoexcept |
Decide whether totalOps warrants parallel dispatch, based on work volume.
Complements shouldParallelize by gating on total arithmetic work rather than task count. At very low per-unit cost (e.g. distance kernels at d=2) the chunk-count gate can pass while the per-worker workload is dwarfed by dispatch overhead; this check prevents fan-out when the per-worker op budget would not amortize the pool submit/wait syscalls.
| totalOps | Approximate total arithmetic operation count across all workers. |
| minOpsPerWorker | Minimum per-worker op budget that amortizes dispatch overhead. |
true when fan-out pays, false otherwise.
|
inlinenodiscardnoexcept |
Block count for a fan-out over n rows that lets work-stealing balance heterogeneous cores.
parallelForBlocks with exactly workerCount blocks hands each worker one block, so a slower core (a different-clocked or different-cache CCD) gates the join while faster cores idle. Oversubscribing the block count gives DynamicChunked the slack to let faster cores claim more blocks. The count is capped so each block keeps at least minRowsPerBlock rows, which bounds the per-block dispatch overhead, and never drops below workerCount.
| n | Row count being partitioned. |
| minRowsPerBlock | Lower bound on rows per block; caps the oversubscription at small n. |
n.
|
inlinenodiscardnoexcept |
|
inlinestaticnodiscardnoexcept |
| OwnedPool* clustering::math::Pool::pool = nullptr |