strummachine / sm-audiokit

0 stars 0 forks source link

Constant CPU burn from AURemoteIO::IOThread #7

Closed banjerluke closed 2 years ago

banjerluke commented 2 years ago

Here is what Strum Machine's CPU usage is like during playback; I happened to catch it at 0% although it's usually between 1% and 5%. "Other Processes" jumps around a lot, but it doesn't seem to be much higher during playback, if at all.

Strum Machine CPU usage

Memory usage is also very reasonable:

image

I wouldn't be surprised if these numbers are inaccurate; perhaps Cordova's browser execution time isn't being captured by the profiler. Still, I can crank up the BPM to crazy amounts and there's no impact on the responsiveness of the app.


On the other hand, here's what I get in our XCode project with 80 AudioPlayers:

image

All the CPU usage is basically coming from AURemoteIO::IOThread, which is steady whether players are going or not. Memory is at 175 MB, with no players buffered.

If I bring the player count down to 8, the CPU usage hovers around 10%, with memory at 39 MB.


In the Cordova testbed project, with 80 AudioPlayers, CPU usage seems to be around 30%, rising up to 40+%, with memory rising up to 150 MB:

image

Memory and CPU use does not decrease when playback is stopped.


I tried calling .bypass() on nodes that weren't in use; that made some difference, but not a ton, and it led to random errors.

Since resource usage does not go down when playback is stopped, I don't think this has anything to do with loading/decoding audio data.

With #6 fixed, the situation is improved, so it may not be the end of the world if this isn't improved... but it seems like quite a waste to be using so much CPU (and battery) when not actually doing that much...

Do any ideas for reducing resource usage come to mind?

banjerluke commented 2 years ago

This is actually not that big of a problem anymore, after I fixed #6, so maybe we can let it slide for now... unless you have any ideas off the top of your head...

banjerluke commented 2 years ago

Closing for now. Notes to future self:

VariSpeed is the biggest CPU hog, followed by Fader (I think). Fader's pretty mandatory, but I could get rid of VariSpeed if I add pre-pitchshifted MP3s to the audio packages.

For that to happen, you need to:

So we'll keep VariSpeed for now in order to ship faster, but we'll plan on getting rid of it in the near future.

maksutovic commented 2 years ago

I'll also reach out to audiokit folks and see if there are any strategies that we're not employing.

banjerluke commented 2 years ago

Hang on, I just re-checked .bypass() and it does seem to be doing the trick...

banjerluke commented 2 years ago

Yup, bypassing the node bypasses processing as well! Not sure why I didn't see that before.

Will push a little change to SamplePlayer.swift in a minute that bypasses the node unless playbackRate is not 1.

banjerluke commented 2 years ago

Well, that's odd. It seems that even if the majority of VariSpeed nodes are bypassed/stopped, just having one or a few nodes running brings the CPU burn right back to where it was. 😂

Leaving the bypassing logic in there since it doesn't hurt anything, but I may still try to eliminate the need for playback rate adjustments in the future.

Clem23 commented 7 months ago

Hello, I face the same issue in a different context using that lib (https://github.com/tkier/GameSoundEngine).

At startup an array of 20 AVAudioPlayerNode and 20 AVAudioUnitTimePitch is created.

When connecting the AVAudioUnitTimePitch cause the CPU to raise and to keep high even if not sound is played.

My work around is to connect the used AVAudioUnitTimePitch to the engine before play and disconnect it after stop but I keep them attached to engine.

That way my CPU go back to 0% when no sound is played and so far I didn't notice any drop in performance.