I just got a new Macbook Pro M1 and I noticed that on a JUCE app that we’re developing, CPU performance on the audio thread is way off when using the
AudioIODeviceCombiner (i.e. when using built-in speaker/mic). Not only way higher compared with a similar Intel Mac, but very inconsistent, jumping up and down. There also seems to be some correlation between the GUI/message thread and the audio thread, as when the window is resized continuously, the audio thread CPU drops and becomes stable (probably pushing the core or workgroup into P mode).
After looking over the code base and profiling, searching, etc. I stumbled on this guide from Apple on using the newish (MacOS 11) Audio Workgroups API.
I don’t see any mentions of this API in the JUCE CoreAudio code or the forums. Am I missing something obvious?
I tried hacking this into
AudioIODeviceCombiner::run() myself and it makes a huge difference - the audio CPU meter becomes stable again and satisfyingly low.
Anyone else noticed this? It would be great if JUCE could look at this as I don’t want to have to use my hacky patch.
Perhaps the title of my post was misleading because i’m not so much talking about thread priority as the behavior of the audio thread, which is always set to priority of 9.
I read that thread before writing this post and it doesn’t mention anything about Audio Workgroups or issues with audio thread performance.
Joining threads to CoreAudio HAL A… | Apple Developer Forums
and this guide…
… show the relevent code for adding the device combiner thread to the audio device workgroup.
We’re currently updating Thread to make use of modern performance classifications. These changes may well fix this issue you’re seeing, but I will check it out.
It’s simple to recreate by just taking the AudioSettingsDemo and adding some heavy processing load, like in the
AudioPerformanceTest with a relatively small buffer size, and then check for xruns and fluctuating CPU usage when using AudioIODeviceCombiner VS using a single device for IO.
But, the problem seems most apparent on the faster M1 macbook pros with 10 cores. It doesn’t seem as much (if at all) of a problem on the M1 Airs for some reason.
The M1 performance issue is a known one, the higher core M1 variants have fewer efficiency cores. Which version of JUCE are you currently targetting?
When I wrote this originally I was building against JUCE 7.0.0 with XCode 13.4.1. But, I just tested JUCE 7.0.1 and there’s no improvement on the issue.
When you say M1 performance is a known issue, do you mean in general? Or as it relates to JUCE code?
Just to be clear, the issue goes away if you use the Audio Workgroup API as described above, so it seems JUCE specific to me. Also, it is not a general audio performance issue as it runs fine when you use the same device for input and output.
pthread API used on macOS doesn’t work very well with the M1 platforms; a
pthread priority below four will lock the thread to the E cores, which, ironically, on the higher performance variants causes a significant performance disparity due to having 2 vs 4 E cores.
I inquired about the JUCE version as a fix was applied recently that prevented low-priority threads. I tested our new code with
AudioDeviceCombiner, and it was as stable on my M1, but I have the M1 with 4 E Cores.
We’re currently transitioning our native threading code to use modern threading priority classifications and APIs (QoS on Apple platforms).
The Audio Workgroup API is something we’re still looking into and where/if it fits into our Thread API.