@@ -226,27 +226,39 @@ _dispatch_workq_monitor_thread_pool(void *context DISPATCH_UNUSED)
226
226
dispatch_workq_manager_t mgr = _dispatch_workq_get_default_manager ();
227
227
dispatch_queue_t dq = _dispatch_workq_get_default_root_queue ();
228
228
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 );
247
261
}
248
- } else {
249
- _dispatch_debug ("workq: %s is empty; skipping analysis of /proc" , dq -> dq_label );
250
262
}
251
263
}
252
264
0 commit comments