Skip to content

Commit 0f7f060

Browse files
authored
Merge pull request #36290 from mikeash/cache-global-dispatch-queues
[Concurrency] Cache the queue returned from dispatch_get_global_queue.
2 parents 78ace58 + 01f1a2d commit 0f7f060

File tree

1 file changed

+31
-7
lines changed

1 file changed

+31
-7
lines changed

stdlib/public/Concurrency/GlobalExecutor.cpp

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,33 @@ static void __swift_run_job_main_executor(void *_job) {
186186
swift_job_run(job, ExecutorRef::mainExecutor());
187187
}
188188

189+
static constexpr size_t globalQueueCacheCount =
190+
static_cast<size_t>(JobPriority::UserInteractive) + 1;
191+
static std::atomic<dispatch_queue_t> globalQueueCache[globalQueueCacheCount];
192+
193+
static dispatch_queue_t getGlobalQueue(JobPriority priority) {
194+
size_t numericPriority = static_cast<size_t>(priority);
195+
if (numericPriority >= globalQueueCacheCount)
196+
fatalError(0, "invalid job priority %#zx");
197+
198+
auto *ptr = &globalQueueCache[numericPriority];
199+
auto queue = ptr->load(std::memory_order_relaxed);
200+
if (SWIFT_LIKELY(queue))
201+
return queue;
202+
203+
// If we don't have a queue cached for this priority, cache it now. This may
204+
// race with other threads doing this at the same time for this priority, but
205+
// that's OK, they'll all end up writing the same value.
206+
queue = dispatch_get_global_queue((dispatch_qos_class_t)priority,
207+
/*flags*/ 0);
208+
209+
// Unconditionally store it back in the cache. If we raced with another
210+
// thread, we'll just overwrite the entry with the same value.
211+
ptr->store(queue, std::memory_order_relaxed);
212+
213+
return queue;
214+
}
215+
189216
#endif
190217

191218
void swift::swift_task_enqueueGlobal(Job *job) {
@@ -232,9 +259,7 @@ void swift::swift_task_enqueueGlobal(Job *job) {
232259

233260
JobPriority priority = job->getPriority();
234261

235-
// TODO: cache this to avoid the extra call
236-
auto queue = dispatch_get_global_queue((dispatch_qos_class_t) priority,
237-
/*flags*/ 0);
262+
auto queue = getGlobalQueue(priority);
238263

239264
dispatch_async_f(queue, dispatchContext, dispatchFunction);
240265
#endif
@@ -256,9 +281,8 @@ void swift::swift_task_enqueueGlobalWithDelay(unsigned long long delay, Job *job
256281

257282
JobPriority priority = job->getPriority();
258283

259-
// TODO: cache this to avoid the extra call
260-
auto queue = dispatch_get_global_queue((dispatch_qos_class_t) priority,
261-
/*flags*/ 0);
284+
auto queue = getGlobalQueue(priority);
285+
262286
dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, delay);
263287
dispatch_after_f(when, queue, dispatchContext, dispatchFunction);
264288
#endif
@@ -277,7 +301,7 @@ void swift::swift_task_enqueueMainExecutor(Job *job) {
277301
dispatch_function_t dispatchFunction = &__swift_run_job_main_executor;
278302
void *dispatchContext = job;
279303

280-
// TODO: cache this to avoid the extra call
304+
// This is an inline function that compiles down to a pointer to a global.
281305
auto mainQueue = dispatch_get_main_queue();
282306

283307
dispatch_async_f(mainQueue, dispatchContext, dispatchFunction);

0 commit comments

Comments
 (0)