Hello,
We have a multi-platform project and we noticed there is a big performance overhead related to calling setVolume, getPlaybackState, setParameterByID and set3DAttributes on EventInstances, from multiple threads. While this logic is present on other platforms, this issue seems exclusive to the PS5.
To give it a bit more context, we have 4 fiber jobs, each running on a separate thread, responsible with adjusting the volume on multiple EventInstances.
Looking at RAZOR CPU profiler measurements, we saw these jobs stall a lot due to multiple mutex waits called on setVolume (e.g, on the 4 threads, each one takes 20ms, while if we attempt to process audio on a single thread, it takes 1ms). We wanted to know if there are best practices when dealing with multiple setVolume calls.
Grouping these Instances into Groups and performing a single setVolume is not feasible as the instances’ volumes are rather independent. Additionally, we also checked if the command buffer was getting filled and while getBufferUsage accuses around 3/4 stalls for around 0.007s, increasing the command buffer memory does not yield any significant results.
Our Technology Specs
Custom C++17 Engine
FMOD: v2.03.13
PS5 SDK: 12.00.00.43
For best practices, you could consider strategies to reduce the volume of API calls. Each time a command is written we aquire a lock around the command queue. If writing the command fails due to the queue being full, we increase the size of the command queue and try writing the command again- all the while holding the command queue crit.
Any other thread attempting to write to the command queue will be blocked while this is occurring, in particular most set and get calls, including the ones you’ve identified.
Expanding the command buffer memory may resolve this with a sufficiently large buffer size- but you would still get stalls from each of the set/get calls that independently aquire the command queue crit.
So if 3/4 of the stalls you are seeing are coming from expanding the command queue size, it sounds like you might have a high volume of API calls, and you may want to consider strategies to reduce the amount of calls occuring. Not sure if any of these apply to you, but as examples:
-
Skip identical API calls:
Something that doesn’t move doesn’t need set3DAttributes called on it every frame- by caching the last position you can check if the position has changed since the last game loop, and skip set3DAttributes if it hasn’t. The same applies to setParameterByID with the same parameter value every tick.
-
Throttle state changes:
Used in conjunction with the above- if the position or parameter is moving by a small amount and wouldn’t make much of an audible difference, don’t commit to a setVolume/setParameterByID/set3DAttributes until it crosses some threshold.
-
Add distance culling for API calls:
If the listener is outside the EventInstance’s max distance you might not need to call setVolume, getPlaybackState, or setParameterByID on it every frame.
As for why this is only occurring on PS5 I’m not sure. I am finding synchronization occurs more slowly on PS5 in general, but all in the realm of microseconds from my testing- nothing like the 20ms you are seeing.
Can you please upload this Razor CPU capture to your FMOD Profile so I can take a look?
Thank you for the reply. As for your request, I have uploaded the capture.