Xcode 14 beta: Thread Performance Checker

This is not strictly Swift-related, but priority inversion has been such a topic during the design of Swift Concurrency, and I wanted to thank someone.

You don't quite know what "priority inversion" is, how to recognize it, how to fix it? I bet you're not alone.

Rejoice: Xcode 14 beta ships with a new diagnostic tool that emits purple runtime warnings when our apps misuse their threads, and have a high-priority thread wait on a low-priority thread:

The Thread Performance Checker is enabled in the scheme editor:

I just met a real-life example: in GRDB, an SQLite database runs on a DispatchQueue whose default quality of service is DispatchQoS.default. The Thread Performance Checker was able to diagnose that performing a synchronous database access from the main thread was a case of priority inversion. The runtime warning can be removed by granting SQLite a .userInitiated qos, or by removing all sync accesses from the main thread. :heart_eyes:

If the people responsible for this feature are reading this forum, please be assured your work is noticed, and warmly welcome :+1:


On a related note, the thread sanitizer finally works with Swift concurrency, so I can finally get rid of my duplicate test runs with it enabled that don't test the concurrency features.

However, it does seem like this new "Thread Performance Checker" setting is not available in test plans. Filed FB10072839.


Isn't it just a problem when using a semaphore/mutex/lock/etc.? The system doesn't know at runtime where the semaphore will be signaled from but when it finally happens, it can generate the purple warning. When you are using DispatchQueue's sync mechanism, it can temporarily increase the priority of that other queue, so using queues with different priorities is not a problem.

Although you should probably not do that either. Just display loading and refresh through a callback when data is ready. (The queue priority should still probably be .userInitiated in this case)

pthread_mutex_t, os_unfair_lock_t, and NSLock all donate priority, semaphores don't, rwlocks don't.