This came up in a refactor of some code that was observing UserDefaults for changes to a particular key (very similar to what is described here). The code used to use the older objc method, which will crash/leak things if the observation calls are unbalanced. Migration to this newer API resolves those issues, but left the lingering questions about the ownership semantics, and whether the observation can be invalidated multiple times, etc.
Post
Replies
Boosts
Views
Activity
Thank you for the quick reply – I agree the API is far nicer than its predecessor(s)! For reference, I filed feedback FB15809140 regarding the dearth of documentation.
Thanks for the feedback @eskimo. You actually helped clarify the point about QoS overrides not being reported via qos_class_self() in a recent other question of mine, which was very helpful in this subsequent investigation. The reason I used qos_class_self() in the example was mostly for convenience, since both the other tools require a bit more overhead to illustrate the same thing (though I have used taskinfo and it reports the same behavior).
I believe the topic here is a bit different than QoS 'overrides', as it's more a question of how a queue's QoS is to be resolved when there is ambiguity between the explicit qos parameter and the QoS value of its target queue. IIUC, this value should essentially be known (or knowable) when the queue is constructed, at least in most cases. In the 'Modernizing Grand Central Dispatch Usage' from WWDC 2017, there is a segment explaining how queue hierarchies are supposed to interact with QoS, and at one point it's stated that:
Another common use case would be to put a label on the mutual exclusion queue to provide a floor of execution so that nothing in this tree can execute below this level, so [utility] in this example.
To me, this, along with the documentation for dispatch_set_target_queue which states:
A dispatch queue inherits the minimum quality-of-service level from its target queue.
suggests that the QoS of the target queue should govern the minimum 'effective' QoS for submitted work items (again, assuming no other QoS rules are in play).
However, upon further research, I did find that there is this additional statement from the docs for dispatch_queue_attr_make_with_qos_class alluding to this issue:
The quality-of-service value you specify using this function takes precedence over the priority level inherited from the dispatch queue’s target queue.
That, combined with what looks like the relevant logic from the open source libdispatch code probably explains why I'm observing this behavior, though it still puzzles me if this is actually intended. I guess fundamentally, I would assume that both creating a queue and immediately setting its target or using the 'atomic' constructor that does both things at once would result in the same end state, at least in regards to the QoS topic here.
Quinn, thank you (as usual) for the extremely useful suggestions! taskinfo in particular very clearly provided evidence of the expected behavior. By setting a breakpoint on a utility-qos queue right before and after enqueuing a user-initiated-qos block, I could see both the req workloop servicer override and eff thread qos move from THREAD_QOS_UTILITY to THREAD_QOS_USER_INITIATED immediately after submitting the higher-priority block (using sudo taskinfo --threads <pid>). The System Trace Instrument template also looks promising, though it surfaces so much information I was unable to clearly identify the QoS changes (no doubt I just need to research how the tool works a bit more). The thread_info approach also seems intriguing, though I haven't quite figured out what the right form of invocation is to produce that data.
For posterity, I also was pointed in the direction of the spindump tool, which also yields some insight into the QoS boosting/propagation behavior. In particular running spindump -timeline <pid> and then running my test code produced output for the relevant thread like: thread QoS user interactive (requested utility, promote user interactive, workloop servicer override utility).
I've spent the past week or so using the 'animation hitches' instrument and have been experiencing the same issue ('commits' track has no data). Additionally, the 'user events', 'renders', 'gpu' tracks are also empty. Furthermore, I've yet to be able to get the 'Display' instrument to produce anything (as I understand it, it should be included with the hitches template, and contain VSYNC data, but it's always been empty and/or missing for me). Following the 'all processes' recording technique also didn't seem to fix the issues.
Is there any updated guidance on this? Should we expect these tools to work?
Xcode Version: 13.3.1 (13E500a)
iOS Version: 14.4
macOS Version: 12.5
Regards,
-Jamie