34 using TaskFn = void (*)(
void* context, std::uint32_t task_index)
noexcept;
93 return current_audio_workgroup_publication().workgroup;
98 bool running() const noexcept {
return running_.load(std::memory_order_acquire); }
100 return worker_backoff_count_.load(std::memory_order_relaxed);
103 return worker_idle_sleep_count_.load(std::memory_order_relaxed);
109#ifdef PULP_GRAPH_RUNTIME_WORKER_POOL_TEST_HOOKS
114 assert(!running_.load(std::memory_order_acquire));
115 scheduling_receipt_hook_for_test_ = hook;
116 scheduling_receipt_context_for_test_ = context;
121 void set_fallback_join_hook_for_test(
bool (*hook)(
void*)
noexcept,
122 void* context)
noexcept {
123 assert(!running_.load(std::memory_order_acquire));
124 fallback_join_hook_for_test_ = hook;
125 fallback_join_context_for_test_ = context;
127 bool configured_audio_workgroup_uses_fallback_for_test() const noexcept {
128 return current_audio_workgroup_publication().fallback_when_null;
134 void set_worker_park_hook_for_test(
void (*hook)(
void*)
noexcept,
135 void* context)
noexcept {
136 assert(!running_.load(std::memory_order_acquire));
137 worker_park_hook_ = hook;
138 worker_park_context_ = context;
145 void keep_workers_hot_for_test() noexcept {
146 assert(!running_.load(std::memory_order_acquire));
147 keep_workers_hot_for_test_ =
true;
153 bool try_hold_cold_transition_gate_for_test() noexcept {
154 bool expected =
false;
155 return cold_transition_gate_.compare_exchange_strong(
156 expected,
true, std::memory_order_acq_rel, std::memory_order_acquire);
158 void release_cold_transition_gate_for_test() noexcept {
159 cold_transition_gate_.store(
false, std::memory_order_release);
162 void pause_workgroup_transition_for_test() noexcept {
163 transition_pause_released_for_test_.store(
false, std::memory_order_release);
164 transition_pause_reached_for_test_.store(
false, std::memory_order_release);
165 transition_pause_enabled_for_test_.store(
true, std::memory_order_release);
167 bool workgroup_transition_pause_reached_for_test() const noexcept {
168 return transition_pause_reached_for_test_.load(std::memory_order_acquire);
170 void release_workgroup_transition_for_test() noexcept {
171 transition_pause_released_for_test_.store(
true, std::memory_order_release);
173 void clear_workgroup_transition_pause_for_test() noexcept {
174 transition_pause_enabled_for_test_.store(
false, std::memory_order_release);
177 void seed_reheat_state_for_test(std::uint32_t
worker_count,
178 std::uint32_t active_worker_threads,
179 bool reheat_requested)
noexcept {
181 active_worker_threads_.store(active_worker_threads, std::memory_order_release);
182 reheat_requested_.store(reheat_requested, std::memory_order_release);
184 void clear_transient_reheat_if_no_worker_cold_for_test() noexcept {
185 clear_transient_reheat_if_no_worker_cold();
187 bool reheat_requested_for_test() const noexcept {
188 return reheat_requested_.load(std::memory_order_acquire);
196 void run(std::uint32_t task_count,
TaskFn fn,
void* context)
noexcept;
199 struct AudioWorkgroupPublication {
200 void* workgroup =
nullptr;
201 std::uint64_t generation = 0;
202 bool fallback_when_null =
true;
205 AudioWorkgroupPublication current_audio_workgroup_publication() const noexcept;
208#if defined(PULP_GRAPH_RUNTIME_WORKER_POOL_TEST_HOOKS)
212 AudioWorkgroupPublication audio_workgroup_publication_for_test() const noexcept {
213 return current_audio_workgroup_publication();
218 bool workers_acknowledged_current_audio_workgroup() const noexcept;
219 void publish_audio_workgroup(
void* workgroup,
220 bool fallback_when_null) noexcept;
221 void worker_loop(
std::uint32_t worker_index) noexcept;
222 void clear_transient_reheat_if_no_worker_cold() noexcept;
224 std::uint32_t worker_index,
std::uint32_t task_count) noexcept;
230 void run_range(
std::uint32_t worker_index) noexcept;
233 std::uint32_t worker_count_ = 0;
240 std::atomic<
std::uint64_t> audio_workgroup_sequence_{2};
241 std::atomic<void*> audio_workgroup_{
nullptr};
242 std::atomic<bool> audio_workgroup_fallback_when_null_{
true};
243 std::unique_ptr<std::atomic<std::uint64_t>[]> worker_workgroup_generation_;
244 std::unique_ptr<std::atomic<bool>[]> worker_workgroup_join_succeeded_;
249 bool (*fallback_join_hook_for_test_)(
void*)
noexcept =
nullptr;
250 void* fallback_join_context_for_test_ =
nullptr;
251 void (*worker_park_hook_)(
void*)
noexcept =
nullptr;
252 void* worker_park_context_ =
nullptr;
253 bool keep_workers_hot_for_test_ =
false;
257 void* scheduling_receipt_context_for_test_ =
nullptr;
265 void* context_ =
nullptr;
266 std::uint32_t task_count_ = 0;
270 alignas(64) std::atomic<std::uint64_t> epoch_{0};
271 alignas(64) std::atomic<bool> stopping_{
false};
272 alignas(64) std::atomic<bool> running_{
false};
273 alignas(64) std::atomic<bool> cold_transition_gate_{
false};
274 alignas(64) std::atomic<bool> reheat_requested_{
false};
279 alignas(64) std::atomic<std::uint64_t> workgroup_prepare_epoch_{0};
280 alignas(64) std::atomic<std::uint32_t> active_worker_threads_{0};
286 alignas(64) std::atomic<std::uint64_t> completed_{0};
289 std::uint64_t completed_base_ = 0;
294 alignas(64) std::atomic<bool> in_run_{
false};
295 alignas(64) std::atomic<std::uint64_t> worker_backoff_count_{0};
296 alignas(64) std::atomic<std::uint64_t> worker_idle_sleep_count_{0};
300 std::atomic<bool> transition_pause_enabled_for_test_{
false};
301 std::atomic<bool> transition_pause_reached_for_test_{
false};
302 std::atomic<bool> transition_pause_released_for_test_{
true};