Skip to content

Commit 0ea540c

Browse files
committed
add test for 0 runnable workers and treat as-if overcommit queue
1 parent 143ae0a commit 0ea540c

File tree

1 file changed

+32
-20
lines changed

1 file changed

+32
-20
lines changed

src/event/workqueue.c

+32-20
Original file line numberDiff line numberDiff line change
@@ -226,27 +226,39 @@ _dispatch_workq_monitor_thread_pool(void *context DISPATCH_UNUSED)
226226
dispatch_workq_manager_t mgr = _dispatch_workq_get_default_manager();
227227
dispatch_queue_t dq = _dispatch_workq_get_default_root_queue();
228228
bool work_available = _dispatch_workq_root_queue_has_work(dq);
229-
if (work_available) {
230-
_dispatch_workq_count_runnable_workers(mgr);
231-
int32_t count = _dispatch_pthread_root_queue_thread_pool_size(dq);
232-
233-
_dispatch_debug("workq: %s is non-empty with pool count %d (%d runnable)",
234-
dq->dq_label, count, mgr->runnable_workers);
235-
236-
if (mgr->runnable_workers < mgr->target_runnable_workers) {
237-
int32_t allowed_over = WORKQ_OVERSUBSCRIBE_FACTOR * mgr->target_runnable_workers;
238-
allowed_over = MIN(allowed_over, WORKQ_MAX_TRACKED_WORKERS - mgr->target_runnable_workers);
239-
if (count + allowed_over > 0) {
240-
_dispatch_debug("workq: %s has count %d; requesting 1 additional worker",
241-
dq->dq_label, count);
242-
_dispatch_pthread_root_queue_oversubscribe(dq, 1);
243-
} else {
244-
_dispatch_debug("workq: %s already oversubscribed by %d; taking no action",
245-
dq->dq_label, -count);
246-
}
229+
230+
if (!work_available) {
231+
_dispatch_debug("workq: %s is empty; doing nothing", dq->dq_label);
232+
return;
233+
}
234+
235+
_dispatch_workq_count_runnable_workers(mgr);
236+
int32_t count = _dispatch_pthread_root_queue_thread_pool_size(dq);
237+
238+
_dispatch_debug("workq: %s is non-empty with pool count %d (%d runnable)",
239+
dq->dq_label, count, mgr->runnable_workers);
240+
241+
if (mgr->runnable_workers < mgr->target_runnable_workers) {
242+
// If we are below target there are two cases to consider:
243+
// (a) We are below target, but some workers are still runnable.
244+
// We want to oversubscribe to hit the target, but this
245+
// may be transitory so only go up to a small multiple
246+
// of threads per core.
247+
// (b) We are below target, and no worker is runnable.
248+
// It is likely the program is stalled. Therefore treat
249+
// this as dq was an overcommit queue and create
250+
// another worker unless we have already hit the hard
251+
// limit on the maximum number of workers for dq.
252+
int32_t oversubscribe_limit = WORKQ_OVERSUBSCRIBE_FACTOR * mgr->target_runnable_workers;
253+
int32_t stalled_limit = WORKQ_MAX_TRACKED_WORKERS - mgr->target_runnable_workers;
254+
int32_t limit = mgr->runnable_workers == 0 ? stalled_limit : MIN(stalled_limit, oversubscribe_limit);
255+
if (count + limit > 0) {
256+
_dispatch_debug("workq: adding 1 additional worker to %s", dq->dq_label);
257+
_dispatch_pthread_root_queue_oversubscribe(dq, 1);
258+
} else {
259+
_dispatch_debug("workq: %s already oversubscribed by %d; taking no action",
260+
dq->dq_label, -count);
247261
}
248-
} else {
249-
_dispatch_debug("workq: %s is empty; skipping analysis of /proc", dq->dq_label);
250262
}
251263
}
252264

0 commit comments

Comments
 (0)