parallel_for.h#
Persistent thread pool and block-parallel iteration helper for element-wise kernels.
-
namespace onnx_light
Alias that makes onnx-light headers compatible with code that references
ONNX_LIGHT_NAMESPACE(the macro used in the standard onnx package).Set to
ONNX_LIGHT_NAMESPACEso both names resolve to the same namespace.Symbol-visibility attribute for the public onnx-light C++ API.
Maps the upstream compatibility macro to onnx-light’s explicit proto ABI annotation. This keeps declarations from vendored ONNX headers visible when
lib_onnx_protouses hidden visibility by default.Namespace alias so that ONNX C++ code (and consumers such as onnxruntime) that refers to the literal
onnxnamespace — rather than theONNX_NAMESPACEmacro — resolves to the onnx-light namespace. The standard onnx package lives innamespace onnx; onnx-light usesonnx_light(via ONNX_LIGHT_NAMESPACE), so this alias keeps onnx-light a true drop-in. It is only introduced when the onnx-light namespace differs fromonnx.-
namespace core
-
namespace runtime
Functions
-
int64_t ParallelForThreadCount() noexcept#
Returns the number of participating threads :cpp:func:
ParallelFormay use.When a :cpp:class:
CpuExecutoris installed on the calling thread (see :cpp:class:CpuExecutorScope), the executor’s effective participant count is returned so the reported value describes the workers that actually run the graph. Outside any executor scope it resolves to one participant per detected physical core, falling back to the detected logical-core count and thenstd::thread::hardware_concurrency(). The result is always>= 1and counts the calling thread, which always participates in the work.Returns: The effective participant count, always at least
1.
-
ThreadPool &GlobalThreadPool()#
Returns the process-wide :cpp:class:
ThreadPoolused by :cpp:func:ParallelFor.The pool is constructed on first use with
ParallelForThreadCount() - 1worker threads (the calling thread makes up the last participant) and lives for the remainder of the process. Threads are therefore created once and reused across everyParallelForcall.Returns: A reference to the shared thread pool.
-
template<typename Fn>
void ParallelFor(int64_t total, int64_t grain_size, Fn fn, std::string_view label = {}, std::source_location location = std::source_location::current())# Splits the half-open range
[0, total)into contiguous blocks and invokesfn(begin, end)once per block.Blocks are processed on the :cpp:class:
CpuExecutorinstalled on the calling thread, or on the shared :cpp:func:GlobalThreadPoolwhen the caller runs outside any executor scope (up to :cpp:func:ParallelForThreadCountparticipants, including the calling thread). Whentotalis belowgrain_sizeor only one thread is available the whole range is processed inline on the calling thread, sofnmust be safe to call once with the full range. The three-argument overload accepts a kernel-specificgrain_size; the two-argument overload below uses :cpp:var:kParallelForGrainSize. Every block is disjoint and covers the range exactly once, so the observable result is independent of the number of threads: kernels that only map input elements to output elements (no cross-element accumulation) stay bit-exact.fnis invoked concurrently from several threads and must therefore only touch data disjoint per block (typically writingoutput[begin, end)frominput[begin, end)). It must not throw.- Parameters:
total – Number of iterations. Values
<= 0are a no-op.grain_size – Minimum iterations per parallel block. Must be positive.
fn – Callable invoked as
fn(int64_t begin, int64_t end)for each block, covering[begin, end).
Variables
-
constexpr int64_t kParallelForGrainSize = 1 << 15#
Iteration count below which :cpp:func:
ParallelForruns the whole range inline on the calling thread. Waking worker threads for tiny ranges costs more than the work they save, so small tensors stay single-threaded.
-
class ThreadPool#
- #include <parallel_for.h>
A persistent pool of worker threads that stay alive between parallel regions.
Unlike spawning fresh
std::threadobjects per call, the workers are created once and briefly spin before parking on a condition variable. Nearby regions therefore avoid scheduler wakeup latency without busy-waiting indefinitely.The pool exposes a single primitive, :cpp:func:
Run, that executes a set of indexed blocks with a static assignment: block0runs on the calling thread and blockjruns on workerj - 1. It deliberately offers no reduction/combine step: callers write disjoint output ranges, so results are independent of how blocks map to threads (bit-exact). The pool handles several scenarios:no workers available (single core): every block runs inline on the caller;
a single block: runs inline without touching the workers;
nested calls from inside a running block: run inline to avoid deadlock;
concurrent calls from unrelated threads: serialized so one region runs at a time, each still internally parallel.
Public Types
-
using TaskFn = void (*)(void*, int64_t)#
Type-erased block callable:
fn(context, block_index).
Public Functions
-
explicit ThreadPool(int64_t num_workers)#
Creates a pool with
num_workersparked worker threads.- Parameters:
num_workers – Number of worker threads to spawn. Values
<= 0create a pool with no workers, in which case :cpp:func:Runexecutes every block on the caller.
-
ThreadPool(int64_t num_workers, ThreadPoolOptions options)#
Creates a pool with explicit startup and spin behavior.
-
ThreadPool(const ThreadPool&) = delete#
-
ThreadPool &operator=(const ThreadPool&) = delete#
-
~ThreadPool()#
-
inline int64_t worker_count() const noexcept#
Returns the number of worker threads (the calling thread is not counted).
Returns: The worker-thread count,
>= 0.
-
template<typename Fn>
inline void Run(int64_t num_blocks, Fn &&fn)# Runs
fn(block)for everyblockin[0, num_blocks), then blocks until all blocks finish.Block
0runs on the calling thread and blockjruns on workerj - 1(static assignment).fnis invoked concurrently and must only touch data disjoint per block; it must not throw.num_blocksmust not exceedworker_count() + 1when workers are used; :cpp:func:ParallelForenforces this.- Parameters:
num_blocks – Number of blocks to run. Values
<= 0are a no-op.fn – Callable invoked as
fn(int64_t block).
Public Static Functions
-
static inline bool InParallelRegion() noexcept#
Returns whether the calling thread is executing a pool region.
Private Functions
-
void StopAndJoin() noexcept#
-
bool SpinForWork(uint64_t last_generation) const noexcept#
-
bool SpinForCompletion() const noexcept#
-
void WorkerLoop(int64_t worker_index)#
Private Members
-
ThreadPoolOptions options_#
-
void *task_ctx_ = nullptr#
-
int64_t num_blocks_ = 0#
-
int64_t started_workers_ = 0#
-
struct ThreadPoolOptions#
- #include <parallel_for.h>
Configures worker startup and spin-before-park behavior for a :cpp:class:
ThreadPool.Public Types
Public Members
-
uint64_t spin_iterations = 1000000#
Number of relax iterations before parking.
-
uint64_t spin_duration_ns = 0#
Duration in nanoseconds to spin before parking. Used only when
spin_iterationsis zero.
-
WorkerStartFn worker_start = nullptr#
Optional callback invoked once by every worker before accepting work.
-
void *worker_start_context = nullptr#
Context passed to :cpp:var:
worker_start.
-
uint64_t spin_iterations = 1000000#
-
namespace detail
Typedefs
-
using ParallelRangeFn = void (*)(void*, int64_t, int64_t)#
Functions
-
void ParallelForErased(int64_t total, int64_t grain_size, void *task_ctx, ParallelRangeFn task_fn)#
-
void ParallelForErasedProfiled(int64_t total, int64_t grain_size, void *task_ctx, ParallelRangeFn task_fn, ParallelRegionCollector *collector, std::string_view label, std::source_location location)#
-
using ParallelRangeFn = void (*)(void*, int64_t, int64_t)#
-
int64_t ParallelForThreadCount() noexcept#
-
namespace runtime
-
namespace core