BGProcessingTask Terminated Due to Signal 9 for CPU Utilization?

I'm scheduling a long-running, suspendable, CPU heavy ML inference task to be run when device is on power with BGProcessingTask. According to Apple, I'm supposed to get unlimited CPU for a couple minutes, then a few seconds to stop with the time-expired callback. When I run my task manually (with the LLDB command from Apple's BGTasks documentation) everything works fine.

However, when the task runs organically in the background, it's killed after about a minute with
Code Block
Terminated due to signal 9

I checked the reason from device logs and it's due to CPU utilization
Code Block
Event: cpu usage Action taken: Process killed CPU: 48 seconds cpu time over 50 seconds (97% cpu average), exceeding limit of 80% cpu over 60 seconds

This doesn't make any sense, as the whole point of BGProcessingTask is disabling the CPU limits for a few minutes to run big tasks in the background.

See this short clip: https://developer.apple.com/videos/play/wwdc2019/707/?time=1069

CPU Monitor is a feature in our systems that automatically terminates apps that use too many CPU cycles in the background in order to protect user's battery life.For the first time ever, we're giving you the ability to turn that off for the duration of your processing task so you can take full advantage of the hardware while the device is plugged in.And finally, we'll make sure that you're eligible to run these tasks as long as you request them when your app is foreground or if your app has been recently used in the foreground.


Any idea why this is happening?

Full callstack:

https://paste bin.com/aaM264Pe
First off, please file a bug on this and please post the bug number here once it's it's filed, as I agree this doesn't look right.

Having said that, can you verify the details of exactly how/when this happened? The one oddity in the log is that you're running significantly earlier in than I'd expect*, but that could be because your usage pattern is unusual or simply a time zone misunderstanding. Do you know when this occurred in local time and was the device fully idle when it happened? The one way I could see this happening is if the background task triggered while the device was being actively used, but that shouldn't happen unless something external forced the task to fire**?

* The "normal" time window for processing task is basically "2 am in the middle of the night" when your device is constantly idle, though "night" here is actually defined by the users habits, not actual wall time. So a night shift works "night time" will end up being shifted to the middle of the day.

**Strictly speaking, LLDB would actually trigger this exact issue, however, part of what LLDB does is disable most of the normal watchdog systems so that they don't interfere with normal debug activity.

Kevin Elliott
DTS Engineer, CoreOS/Hardware

Hi Kevin,

Apologies for the delayed response, this feature was shelved for a while but I'm back now.

I made a radar here https://feedbackassistant.apple.com/feedback/9041204 and submitted the logs you requested but have gotten no response. I triggered natural background by plugging in the iPhone/iPad, going to the home screen, and leaving it idle for 10-30 minutes.

So, I looked over both the bug and the earlier stackshot and I do have a few questions/suggestions:

-This would probably be worth filing a TSI about. Everything below is basically "first guess" pass at this, not the sort of in depth investigation a TSI would provide:

How to Submit a TSI

-Before doing anything else, try reproducing the issue with out doing ANY of the actually "work" you're actually planning to do. I'd basically just replace your entire dispatch block with a some some sort of endless calculation. This is basically just a quick an easy way to prove/disprove that something about the actual work you're doing is triggering the crash.

-I don't think it's. direct cause but you should not be doing this sort of long running work in a dispatch block. GCD works well for processing small amounts, but it shouldn't be used as generic thread API. That's particularly true when doing any sort of recursion, since you can't control the tread stack size of a GCD thread.

-Does your app include any background categories, particularly the "audio" background category? Different background categories apply their own limitations on the processes they manage and I could see those interactions getting quite complicated if/when multiple there are multiple reasons for your app to be awake. That actually connects to here:

"I triggered natural background by plugging in the iPhone/iPad, going to the home screen, and leaving it idle for 10-30 minutes."

That is NOT what I would have normally expected, however, if your app was a awake for other reason ("audio" being the most likely explanation), then that might explain both why your app was run so early (it was already awake) and where the limitation came from (the audio system basically "overrode" BGProcessingTask).

-Kevin Elliott, DTS Engineer, CoreOS/Hardware

BGProcessingTask Terminated Due to Signal 9 for CPU Utilization?
 
 
Q