Clustering
C++20 header-only: DBSCAN, HDBSCAN, k-means.
Loading...
Searching...
No Matches
clustering::math::Pool Struct Reference

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>
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>
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>
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

OwnedPoolpool = nullptr
 Underlying pool, or nullptr to force serial execution.

Detailed Description

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.

Note
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.

Definition at line 109 of file thread.h.

Member Function Documentation

◆ forkJoin2()

template<class HintsT = citor::HintsDefaults, class FnA, class FnB>
void clustering::math::Pool::forkJoin2 ( FnA && a,
FnB && b ) const
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.

Definition at line 213 of file thread.h.

◆ inclusiveScan()

template<class HintsT = citor::HintsDefaults, class T, class PrefixFn>
T clustering::math::Pool::inclusiveScan ( std::span< const T > in,
std::span< T > out,
T identity,
PrefixFn prefix )
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.

Template Parameters
HintsTHint type whose static-constexpr members drive compile-time policy.
Parameters
inInput span.
outOutput span; same length as in.
identityMonoid identity for prefix.
prefixAssociative binary combiner.
Returns
Inclusive accumulator at the right edge of the scan.

Definition at line 473 of file thread.h.

◆ parallelForBlocks()

template<class HintsT = citor::HintsDefaults, class Body>
void clustering::math::Pool::parallelForBlocks ( std::size_t first,
std::size_t last,
std::size_t numBlocks,
Body body )
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.

Template Parameters
HintsTHint type whose static-constexpr members drive compile-time policy.
BodyCallable invocable as Body(std::size_t lo, std::size_t hi).
Parameters
firstInclusive lower bound of the iteration range.
lastExclusive upper bound of the iteration range.
numBlocksRequested block count; 0 selects the backend's default partition.
bodyCallable invoked once per block.

Definition at line 239 of file thread.h.

◆ parallelForChunks()

template<class HintsT = citor::HintsDefaults, class Body>
void clustering::math::Pool::parallelForChunks ( std::size_t numChunks,
Body body )
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.

Template Parameters
HintsTHint type whose static-constexpr members drive compile-time policy.
BodyCallable invocable as Body(std::size_t chunkIdx).
Parameters
numChunksTotal number of chunks to dispatch.
bodyCallable invoked once per chunk.

Definition at line 342 of file thread.h.

◆ parallelForExactBlocks()

template<class HintsT = citor::HintsDefaults, class Body>
void clustering::math::Pool::parallelForExactBlocks ( std::size_t first,
std::size_t last,
std::size_t numBlocks,
Body body )
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).

Template Parameters
HintsTHint type whose static-constexpr members drive compile-time policy.
BodyCallable invocable as Body(std::size_t lo, std::size_t hi).
Parameters
firstInclusive lower bound of the iteration range.
lastExclusive upper bound of the iteration range.
numBlocksNumber of contiguous blocks; must be at least 1.
bodyCallable invoked once per block.

Definition at line 268 of file thread.h.

◆ parallelForExactBlocksWithSlot()

template<class HintsT = citor::HintsDefaults, class Body>
void clustering::math::Pool::parallelForExactBlocksWithSlot ( std::size_t first,
std::size_t last,
std::size_t numBlocks,
Body body )
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.

Template Parameters
HintsTHint type whose static-constexpr members drive compile-time policy.
BodyCallable invocable as Body(std::size_t lo, std::size_t hi, std::size_t slot).
Parameters
firstInclusive lower bound of the iteration range.
lastExclusive upper bound of the iteration range.
numBlocksNumber of contiguous blocks; must be at least 1.
bodyCallable invoked once per block with the block's slot index.

Definition at line 307 of file thread.h.

◆ parallelReduce()

template<class HintsT = citor::HintsDefaults, class T, class Map, class Combine>
T clustering::math::Pool::parallelReduce ( std::size_t first,
std::size_t last,
T init,
Map map,
Combine combine )
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.

Template Parameters
HintsTcitor reduction hint type, e.g. citor::HintsDefaults.
TReduction value type.
MapCallable invocable as T(std::size_t lo, std::size_t hi).
CombineCallable invocable as T(T a, T b).
Parameters
firstInclusive lower bound of the iteration range.
lastExclusive upper bound of the iteration range.
initIdentity value.
mapPer-block mapper.
combineProducer-side combiner.
Returns
Combined reduction value.

Definition at line 376 of file thread.h.

◆ parallelRunPlex() [1/2]

template<class HintsT = citor::HintsDefaults, class Phase>
void clustering::math::Pool::parallelRunPlex ( std::size_t nPhases,
std::size_t n,
Phase phaseFn )
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.

Template Parameters
HintsTHint type whose static-constexpr members drive compile-time policy.
PhaseCallable invocable as Phase(std::size_t phaseIdx, std::uint32_t slot, std::size_t lo, std::size_t hi, void* tlsArena).
Parameters
nPhasesNumber of phases to run; 0 is a no-op.
nRow-range upper bound; partitioned per-slot as [n*slot/P, n*(slot+1)/P).
phaseFnCallable invoked once per (phase, slot) pair.

Definition at line 411 of file thread.h.

◆ parallelRunPlex() [2/2]

template<class HintsT = citor::HintsDefaults, class Phase, class PrePhase>
void clustering::math::Pool::parallelRunPlex ( std::size_t nPhases,
std::size_t n,
Phase phaseFn,
PrePhase prePhaseFn,
citor::CancellationToken tok = citor::CancellationToken{} )
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.

Definition at line 494 of file thread.h.

◆ parallelScan()

template<class HintsT = citor::HintsDefaults, class T, class BodyFn, class PrefixFn>
T clustering::math::Pool::parallelScan ( std::size_t n,
T identity,
BodyFn body,
PrefixFn prefix )
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.

Template Parameters
HintsTHint type whose static-constexpr members drive compile-time policy.
TReduction value type.
BodyFnCallable: 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.
PrefixFnCallable: T(T a, T b) cross-chunk reduce.
Parameters
nRange length.
identityIdentity value seeded into pass 1's body and returned for empty ranges.
bodyPer-chunk body invoked twice (once per pass).
prefixCross-chunk binary combiner.
Returns
Inclusive accumulator at the right edge of the scan.

Definition at line 444 of file thread.h.

◆ shouldParallelize()

bool clustering::math::Pool::shouldParallelize ( std::size_t totalWork,
std::size_t minChunk,
std::size_t minTasksPerWorker = 2 ) const
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.

Parameters
totalWorkTotal number of work units (e.g. matrix elements, rows).
minChunkMinimum chunk size that amortizes per-task overhead.
minTasksPerWorkerMinimum chunks per worker required to bother fanning out.
Returns
true when parallel dispatch should yield speedup, false otherwise.

Definition at line 147 of file thread.h.

◆ shouldParallelizeWork()

bool clustering::math::Pool::shouldParallelizeWork ( std::size_t totalOps,
std::size_t minOpsPerWorker = std::size_t{1} << 15 ) const
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.

Parameters
totalOpsApproximate total arithmetic operation count across all workers.
minOpsPerWorkerMinimum per-worker op budget that amortizes dispatch overhead.
Returns
true when fan-out pays, false otherwise.

Definition at line 168 of file thread.h.

◆ stealBlocks()

std::size_t clustering::math::Pool::stealBlocks ( std::size_t n,
std::size_t minRowsPerBlock = 256 ) const
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.

Parameters
nRow count being partitioned.
minRowsPerBlockLower bound on rows per block; caps the oversubscription at small n.
Returns
A block count in [workerCount, workerCount * 8], clamped down for small n.

Definition at line 191 of file thread.h.

◆ workerCount()

std::size_t clustering::math::Pool::workerCount ( ) const
inlinenodiscardnoexcept

Number of worker threads available, or 1 in serial mode.

Returns
The pool's participant / worker count when attached, otherwise 1.

Definition at line 118 of file thread.h.

◆ workerIndex()

std::size_t clustering::math::Pool::workerIndex ( )
inlinestaticnodiscardnoexcept

Stable index of the calling worker thread within the owning pool.

Returns
The worker id reported by the backend's per-thread accessor when invoked from a pool task body, otherwise 0.

Definition at line 131 of file thread.h.

Member Data Documentation

◆ pool

OwnedPool* clustering::math::Pool::pool = nullptr

Underlying pool, or nullptr to force serial execution.

Definition at line 111 of file thread.h.


The documentation for this struct was generated from the following file: