Persistent fork-join worker pool for the levelized parallel graph executor. More...
#include <graph_runtime_worker_pool.hpp>
Classes | |
| struct | SchedulingReceipt |
Public Types | |
| enum class | SchedulingReceiptPhase : std::uint8_t { Published , WorkerAdmission , InlineFallback } |
| using | TaskFn = void (*)(void* context, std::uint32_t task_index) noexcept |
| using | SchedulingReceiptHook = void (*)(const SchedulingReceipt&, void*) noexcept |
Public Member Functions | |
| GraphRuntimeWorkerPool ()=default | |
| ~GraphRuntimeWorkerPool () | |
| GraphRuntimeWorkerPool (const GraphRuntimeWorkerPool &)=delete | |
| GraphRuntimeWorkerPool & | operator= (const GraphRuntimeWorkerPool &)=delete |
| bool | start (std::uint32_t worker_count) |
| void | stop () noexcept |
| void | set_audio_workgroup (void *workgroup) noexcept |
| void | set_audio_workgroup_from_render_context (void *workgroup) noexcept |
| bool | prepare_audio_workgroup_for_render () noexcept |
| void | wait_for_audio_workgroup_update () noexcept |
| void * | configured_audio_workgroup () const noexcept |
| bool | workers_use_current_audio_workgroup () const noexcept |
| std::uint32_t | worker_count () const noexcept |
| bool | running () const noexcept |
| std::uint64_t | worker_backoff_count () const noexcept |
| std::uint64_t | worker_idle_sleep_count () const noexcept |
| std::uint64_t | worker_park_count () const noexcept |
| void | run (std::uint32_t task_count, TaskFn fn, void *context) noexcept |
Persistent fork-join worker pool for the levelized parallel graph executor.
Threads are spawned once at start() (off the audio thread). After a batch they stay hot briefly with a bounded spin/yield loop, then fall back to short cold-idle sleeps. If a later run() arrives while workers are cold, that batch runs inline and requests worker reheating for subsequent batches. run() executes task_count tasks across the pool's threads PLUS the calling (audio) thread, then returns when every participant has completed — no allocation, no lock, no condition variable, and no OS wakeup from run(). The audio callback owns the fork-join; workers never allocate or steal.
Tasks are claimed cooperatively via an atomic cursor, so a task is a small index the caller maps to a unit of work (e.g. a node in the current level). The same pool is reused across blocks. Worker threads enter the audio workgroup or best-effort realtime priority path once, then keep denormals flushed while running every batch.
Lifetime: start()/stop() are control-thread only. run() is audio-thread only and must not overlap a stop(). A run_fn must be RT-safe (no alloc/lock) — the pool only provides the fork-join, not RT-safety of the work itself.
| using pulp::format::GraphRuntimeWorkerPool::SchedulingReceiptHook = void (*)(const SchedulingReceipt&, void*) noexcept |
| using pulp::format::GraphRuntimeWorkerPool::TaskFn = void (*)(void* context, std::uint32_t task_index) noexcept |
|
strong |
|
default |
| pulp::format::GraphRuntimeWorkerPool::~GraphRuntimeWorkerPool | ( | ) |
|
delete |
|
inlinenoexcept |
|
delete |
|
noexcept |
|
noexcept |
|
inlinenoexcept |
|
noexcept |
|
noexcept |
| bool pulp::format::GraphRuntimeWorkerPool::start | ( | std::uint32_t | worker_count | ) |
|
noexcept |
|
noexcept |
|
inlinenoexcept |
|
inlinenoexcept |
|
inlinenoexcept |
|
inlinenoexcept |
|
noexcept |