I was wondering if there is a way, while debugging, to observe the 'QoS boosting' behavior that is implemented in various places to provide priority inversion avoidance. The pthread_override_qos_class_start/end_np header comments specifically say that overrides aren't reflected in the qos_class_self() and pthread_get_qos_class_np() return values. As far as I can tell the 'CPU Report' UI in Xcode also does not reflect this information (perhaps for the reason the header comments call out).
Is there a direct mechanism to observe this behavior? Presumably a heuristic empirical test could be done to compare throughput of a queue that should have its priority boosted and one that should not, but I would prefer a less opaque means of verification if possible. Thanks in advance!
Dispatch
RSS for tagExecute code concurrently on multicore hardware by submitting work to dispatch queues managed by the system using Dispatch.
Posts under Dispatch tag
29 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
Two different crash patterns -- one an abort, the other complaining about a lock being corrupt or owning thread having exited. The first one is:
Thread 1 Crashed:: Dispatch queue: com.apple.root.default-qos.overcommit
0 libsystem_platform.dylib 0x18fc10244 _os_unfair_lock_corruption_abort + 88
1 libsystem_platform.dylib 0x18fc0b788 _os_unfair_lock_lock_slow + 332
2 libobjc.A.dylib 0x18f820c90 objc_sync_enter + 20
3 com.kithrup.TPProvider 0x100d2eee0 closure #3 in TPProvider.startProxy(options:completionHandler:) + 340
4 com.kithrup.TPProvider 0x100d2d980 thunk for @escaping @callee_guaranteed () -> () + 28
5 libdispatch.dylib 0x18fa31910 _dispatch_client_callout + 20
6 libdispatch.dylib 0x18fa34dc8 _dispatch_continuation_pop + 600
7 libdispatch.dylib 0x18fa48be4 _dispatch_source_latch_and_call + 420
8 libdispatch.dylib 0x18fa477b4 _dispatch_source_invoke + 832
9 libdispatch.dylib 0x18fa431f4 _dispatch_root_queue_drain + 392
10 libdispatch.dylib 0x18fa43a04 _dispatch_worker_thread2 + 156
11 libsystem_pthread.dylib 0x18fbdb0d8 _pthread_wqthread + 228
12 libsystem_pthread.dylib 0x18fbd9e30 start_wqthread + 8
while the other one is:
Application Specific Information:
BUG IN CLIENT OF LIBPLATFORM: os_unfair_lock is corrupt, or owner thread exited without unlocking
Abort Cause 198194
Thread 1 Crashed:: Dispatch queue: com.apple.root.default-qos.overcommit
0 libsystem_platform.dylib 0x18fc10220 _os_unfair_lock_corruption_abort + 52
1 libsystem_platform.dylib 0x18fc0b788 _os_unfair_lock_lock_slow + 332
2 libobjc.A.dylib 0x18f820c90 objc_sync_enter + 20
3 com.kithrup.TPProvider 0x104e86ee0 closure #3 in TPProvider.startProxy(options:completionHandler:) +340
4 com.kithrup.TPProvider 0x104e85980 thunk for @escaping @callee_guaranteed () -> () + 28
5 libdispatch.dylib 0x18fa31910 _dispatch_client_callout + 20
6 libdispatch.dylib 0x18fa34dc8 _dispatch_continuation_pop + 600
7 libdispatch.dylib 0x18fa48be4 _dispatch_source_latch_and_call + 420
8 libdispatch.dylib 0x18fa477b4 _dispatch_source_invoke + 832
9 libdispatch.dylib 0x18fa431f4 _dispatch_root_queue_drain + 392
10 libdispatch.dylib 0x18fa43a04 _dispatch_worker_thread2 + 156
11 libsystem_pthread.dylib 0x18fbdb0d8 _pthread_wqthread + 228
12 libsystem_pthread.dylib 0x18fbd9e30 start_wqthread + 8
Our TPProvider, whenever it uses a dispatch queue, uses a custom one, so these are presumably system queues and locks. My best guess would be some XPC command took too long? But that's just WAG.
Any ideas about what is actually going on?
Hi everyone,
I have an AR app that allows for collaborative sessions and synchronizes model state (e.g. rotation, can be changed via slider) using Multipeer Connectivity. The receiving peer parses the data and then uses DispatchQueue.main.async to update the UI (SwiftUI) and the model in SceneKit. Lately I have noticed that this synchronization seems to lag periodically.
To analyze the issue better I compiled this minimal reproducible example: https://github.com/MrMuetze/MCSyncTest
The repository includes a boiled down "Multipeer Connectivity" project that should make this issue reproducible on local devices (maybe even between one device and the simulator). I have also added a readme with a gif that shows the issue.
The synchronization between devices worked like a treat for a long time but recently I have noticed that e.g. a rotation is not as smooth as before on the receiving device. A bit of debugging revealed that the messages are received quickly but then the work that needs to happen on the main thread is periodically delayed.
In the example project the relevant code bit that should be executed on the main thread looks like this:
func session(_: MCSession, didReceive data: Data, fromPeer _: MCPeerID) {
print("received data")
DispatchQueue.main.async {
print("doing stuff")
let doubleVal = data.to(type: Double.self) ?? 0.0
self.internalSliderValue = doubleVal
self.sliderValue = doubleVal
}
}
It updates a published variable sliderValue that is connected to a Slider and a Text UI element.
Regularly (like every 500ms or so) the execution of work on the main thread seems to be delayed. After a short while all outstanding UI updates are executed at once which leads to visual stuttering. This can be observed by looking at the printed messages:
...
received data <-- normal behavior
doing stuff
received data
doing stuff
received data
doing stuff
received data <-- hiccup starts
received data
received data
received data
doing stuff
doing stuff
doing stuff
doing stuff
received data <-- returns to normal behavior
doing stuff
received data
doing stuff
...
I have tried to change the "Quality of Service" to .userInteractive as well as limiting the number of messages that are sent in a certain timeframe (I tried one message every 100ms). Both changes have not helped and even with a much lower number of messages the periodic stuttering remains. Using DispatchQueue.main.sync is also not a solution right now. It does bring the sequence back into original order but the periodic "freeze" of the queue is prevalent there as well. This then leads to a "laggy" execution of what happened on the sending peer device.
I am not very familiar with Profiling an app and using Instruments, but I have captured some timings in regards to the usage of the main thread and some backtraces. From what I can understand the workload of the written code should not be the issue, but rather an underlying system function or library. I can provide more information in regards to the backtraces if needed. Right now I can't really say what would be useful. Below is an image that shows the main thread usage at the very top. This happens when the slider lags as shown in the gif.
I am working with Xcode 15.2 and run the app on iOS 17.3. For devices I use an iPad Pro (2nd gen.) and an iPhone 15 Pro. The issue happens in Debug as well as in Release mode. I can't quite say when the stuttering appeared initially. I wonder if anyone is aware of any changes to iOS or underlying frameworks that could have caused this issue. I am interested in any information about this, if the issue can be resolved or if I have to look for alternative workarounds.
Let me know if I can add any additional information.
Best regards!
Bjoern
I'm looking for a fast and efficient way for user-space to send I/O to my driver. One way I'd have hoped to do this, was through a shared memory ring-buffer.
In the WWDC19 presentation on System Extensions and DriverKit, at roughly 17:00, they mention an IOSharedDataQueueDispatchSource. This doesn't exist in the DriverKit API. An IODataQueueDispatchSource is available, but doesn't seem to be meant to be shared.
In the old IOKit framework, there are similar IOSharedDataQueue and IODataQueue, but they are unavailable in DriverKit.
So, what are my options for implementing a fast, efficient I/O path to my driver?
Hello! I'm developing a SDK and a customer is experiencing a very rare crash (happening for < 10 users) for which there are no clear repro steps.
In the attached backtrace of the crash, there are two threads #13 and #17 which seem to be accessing the same part of the code (named MyMethod2 in the file). Thread #17 is the one crashing during deallocation of some protobuf objects.
We designed MyMethod2 to be called by at most one thread at any point in time by using a serial DispatchQueue.
My question is: can we tell for sure that the threads #13 and #17 shown in the file were executing that shared code simultaneously just by looking at the trace? If so, there'd be a concurrency bug in my code that I need to fix, but I haven't found anything suspicious. If on the other hand, these two threads were both used by the serial queue but at different times, then the problem is elsewhere.
Thank you for your help!
The two threads:
Thread 13 name:
Thread 13:
0 libsystem_kernel.dylib 0x00000001f61a0cb0 write (libsystem_kernel.dylib)
1 CoreFoundation 0x00000001aed14f68 fileWrite (CoreFoundation)
2 CoreFoundation 0x00000001aed14c40 CFWriteStreamWrite (CoreFoundation)
3 [MyHiddenAppName] 0x0000000107b81f8c NSOutputStream.write(_:)
4 [MyHiddenAppName] 0x0000000107ab6640 specialized MyMethod2
5 [MyHiddenAppName] 0x0000000107ab6cf0 partial apply for closure #1 in MyMethod1
6 [MyHiddenAppName] 0x0000000102ba0538 thunk for @escaping @callee_guaranteed () -> () (<compiler-generated>:0)
7 libdispatch.dylib 0x00000001b6c4f6a8 _dispatch_call_block_and_release (libdispatch.dylib)
[...]
Thread 17 name:
Thread 17 Crashed:
0 libswiftCore.dylib 0x00000001a8467d70 _swift_release_dealloc (libswiftCore.dylib)
1 libswiftCore.dylib 0x00000001a8469424 bool swift::RefCounts<swift::RefCountBitsT<(swift::RefCountInlinedness)1>>::doDecrementSlow<(swift::PerformDeinit)1>(swift::RefCountBitsT<(swift::RefCountInlinedness)1>, unsigned int) (libswiftCore.dylib)
2 [MyHiddenAppName] 0x0000000107a45b54 destroy for MyProtoStruct4
3 [MyHiddenAppName] 0x0000000107a55c64 outlined destroy of (MyProtoStruct2.OneOfEnum, MyProtoStruct2.OneOfEnum)
4 [MyHiddenAppName] 0x0000000107a4503c MyProtoStruct4._StorageClass.__deallocating_deinit
5 libswiftCore.dylib 0x00000001a8467d88 _swift_release_dealloc (libswiftCore.dylib)
6 libswiftCore.dylib 0x00000001a8469424 bool swift::RefCounts<swift::RefCountBitsT<(swift::RefCountInlinedness)1>>::doDecrementSlow<(swift::PerformDeinit)1>(swift::RefCountBitsT<(swift::RefCountInlinedness)1>, unsigned int) (libswiftCore.dylib)
7 [MyHiddenAppName] 0x0000000107a6a91c destroy for MyProtoStruct3
[...]
80 [MyHiddenAppName] 0x0000000107ab6108 specialized MyMethod2
81 [MyHiddenAppName] 0x0000000107ab6cf0 partial apply for closure #1 in MyMethod1
82 [MyHiddenAppName] 0x0000000102ba0538 thunk for @escaping @callee_guaranteed () -> () (<compiler-generated>:0)
83 libdispatch.dylib 0x00000001b6c4f6a8 _dispatch_call_block_and_release (libdispatch.dylib)
[...]
crash_backtrace.txt
I want to optimize file reading performance. I believe DispatchIO is the solution. Can anyone give some good pointers?
When calling DispatchQueue.main.async or DispatchQueue.main.sync with a call to self without capturing self, I get a compiler error:
Call to method 'asd' in closure requires explicit use of 'self' to make capture semantics explicit
Since I usually use DispatchQueue.main.async, I'm now used to solving this error by capturing self like this:
DispatchQueue.main.async { [self] in
asd()
}
But this unfortunately doesn't seem to work with DispatchQueue.main.sync:
DispatchQueue.main.async { [self] in
asd()
}
This gives the compiler warning:
Call to method 'asd' in closure requires explicit use of 'self' to make capture semantics explicit; this is an error in Swift 6
This warning only appears for DispatchQueue.main.sync and not for DispatchQueue.main.async. Why? How can I avoid having to prefix every method call with self. in this case?
Swift Concurrency Resources:
DevForums tags: Concurrency
The Swift Programming Language > Concurrency documentation
Migrating to Swift 6 documentation
WWDC 2022 Session 110351 Eliminate data races using Swift Concurrency — This ‘sailing on the sea of concurrency’ talk is a great introduction to the fundamentals.
WWDC 2021 Session 10134 Explore structured concurrency in Swift — The table that starts rolling out at around 25:45 is really helpful.
Swift Async Algorithms package
Swift Concurrency Proposal Index DevForum post
Matt Massicotte’s blog
Dispatch Resources:
DevForums tags: Dispatch
Dispatch documentation — Note that the Swift API and C API, while generally aligned, are different in many details. Make sure you select the right language at the top of the page.
Dispatch man pages — While the standard Dispatch documentation is good, you can still find some great tidbits in the man pages. See Reading UNIX Manual Pages. Start by reading dispatch in section 3.
WWDC 2015 Session 718 Building Responsive and Efficient Apps with GCD [1]
WWDC 2017 Session 706 Modernizing Grand Central Dispatch Usage [1]
Avoid Dispatch Global Concurrent Queues DevForums post
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
[1] These videos may or may not be available from Apple. If not, the URL should help you locate other sources of this info.
Hi, I work on a game for iOS and the framerate decreases progressively when the debugger is attached.
Running it for 2mins, it went from 30 to 1 FPS while rendering a simple static scene.
I narrowed it down to a call to dispatch_async_f which takes longer to execute over time.
clock_t t1 = clock();
dispatch_async_f(queue, context, function);
clock_t t2 = clock();
double duration = (double)(t2 -t1)/(double)CLOCKS_PER_SEC;
Dodumentation says dispatch_async_f is supposed to return immediatly.
So what could explain duration to increases in debug? Am i measuring this incorrectly?
The game is written in mixed C++ and ObjC. It uses Metal as graphic API and GCD for dispatching jobs.
I have Xcode 13.4.1 and test on an iPhone 13 Pro with iOS 15.7.
Thanks.