BGProcessingTaskRequest runs only for 295 seconds before the expiration handler is called on iOS 14.8 - ios

We need to process a lot of data in the background for iOS and came across BGProcessingTaskRequest which is intended for tasks which may take minutes. However in practice, the task is always killed after exactly 295 seconds on my iOS 14.8 device.
Is this the most amount of background processing time we can expect on iOS or are there any other ways to increase the background execution time? If not, is it possible to chain the requests by scheduling the task again in it's own handler?

As you know, they only promise that it “can run for minutes”. One would have hoped that setting the task’s requiresExternalPower, might increase the allotted time as the battery concerns are eliminated, but in my tests, the allotted time is still limited to roughly 5 minutes (tested in iOS 15).
As you suggest, you can schedule another processing request when time expires. In my experiments, though, this subsequent request took even longer before it started and expired even more quickly.
In short, you can chain requests as you suggest, but you are at the mercy of the OS.

Related

FreeRTOS is slow to wake after long processor sleep

(Cross-posted on Electrical Engineering Stack Exchange)
I'm using FreeRTOS in an application which requires the processor to sleep in low power mode for a long time (as long as 12 hours), then wake up in response to an interrupt request. I'm having a problem with the amount of time taken for FreeRTOS to wake up.
Before going to sleep, I disable the scheduler through a call to vTaskSuspendAll().
On waking, I calculate the amount of time that the processor has been asleep, and update FreeRTOS via a call to vTaskJumpTime(). I then make a call to xTaskResumeAll() to restart the scheduler.
The issue I have is that xTaskResumeAll() makes a call to xTaskIncrementTick() once for each tick that has been missed while the processor was asleep (recorded through vTaskJumpTime()). It takes about 12 seconds to wake after an hour asleep (3,600,000 calls to xTaskIncrementTick()).
Much as I'm tempted to modify the FreeRTOS xTaskIncrementTick() function, so that it can jump a number of ticks in one call, experience says that I would be smart to look for a standard way first.
Has anyone found another way to implement this behavior which doesn't result in the long wake-up delay?
This is implemented on an Microchip/Atmel SAM4L (Cortex-M4). I use the AST sub system to record the time that the processor is asleep. The sleep is implemented through BPM sub system bpm_sleep() in RETENTION mode.
FreeRTOS's built in low power support uses vTaskStepTick() to jump the tick count forward in one go. It can do that because it won't calculate a wake time (the time at which it leaves low power mode) past the time it knows a task must unblock because a timeout expired. If you remain in sleep mode past the time a task should have unblocked because its timeout expired you have an error anyway. The best place to get FreeRTOS support is it's dedicated support forum.

`BGAppRefreshTask` vs `BGProcessingTask` understanding timing

I'm trying to understand the distinction between BGAppRefreshTask and BGProcessingTask where for processing Apple's docs say for a process that “takes minutes” whereas refresh they say for a “short request task.” I am iterating through workouts in HealthKit which takes under a minute, so should I be using BGAppRefreshTask?
The BGAppRefreshTask has a time limit of 30 seconds. So if you can't guarantee the task will take less than that time, the BGProcessingTask may probably more appropriate.
This was noted in the WWDC 2019 Session 707 Advances in App Background Execution. The relevant time index is: 18:51

Is there any way not to get CPU-throttled in the background?

I have a CPU task that needs to occur when the app is running in the background (either by way of fetch or silent notification). This task takes about 1s when running in the foreground but about 9s when running in the background. It's basically saving out ~100K textual entries to a database. Whether I use FileHandle operations or a Core Data sqlite solution, the performance profile is about the same (Core Data is a little slower surprisingly).
I don't really want to get into the specifics of the code. I've already profiled the hell out of it and in the foreground it's quite performant. But clearly when the app is running in the background it's being throttled by iOS to the tune of a 9x slowdown. This wouldn't be such a big issue except in response to a silent notification iOS only gives the app 30-40s to complete and this 9s task can put it over the limit. (The rest of it is waiting on subsystems that I have no control over.)
So the question:
Is there any way to tell iOS Hi, yes, I'm in the background but I really need this chunk of code to run quickly and avoid your throttling ? FWIW I'm already running in a .userInitiated qos dispatch queue:
DispatchQueue.global(qos: .userInitiated).async {
// code to run faster goes here
}
Thanks!
First, no. The throttling is on purpose, and you can't stop it. I'm curious if using a .userInitiated queue is actually improving performance much over a default queue when you're in the background. Even if that's true today, I wouldn't bet on that, and as a rule you shouldn't mark something user initiated that is clearly not user initiated. I wouldn't put it past Apple to run that queue slower when in the background.
Rather than asking to run more quickly, you should start by asking the OS for more time. You do that by calling beginBackgroundTask(expirationHandler:) when you start processing data, and then call endBackgroundTask(_:) when you're done. This tells the OS that you're doing something that would be very helpful if you could complete, and the OS may give you several minutes. When you run out of whatever time it gives you, then it'll call your expirationHandler, and you can save off where you were at that point to resume work later.
When you run out of time, you're only going to get a few seconds to complete your expiration handler, so you may not be able to write a lot of data to disk at that point. If the data is coming from the network, then you address this by downloading the data first (using a URLSessionDownloadTask). These are very energy efficient, and your app won't even be launched until the data is finished downloading. Then you start reading and processing, and if you run out of time, you squirrel away where you were in user defaults so you can pick it up again when you launch next. When you're done, you delete the file.

iOS 7 Background Fetch: Large Import Operation

I would like to do a large background fetch and Core Data import which takes between 10 and 50 minutes.
Would that be possible with the background fetch method in iOS 7?
The Apple Docs states that a background fetch should take less than 30 seconds otherwise it will be called less often.
However, if I am ok with my background fetch being called "less often" is there a limitation on what can be done in a background fetch (e.g. Core Data writes) and how long it may take?
Yes, the watch dog will eventually kill your application. The length of time that your application gets to run is dependent on the needs of the system and can vary by a large amount.
If you have an import that takes that long then I would suggest designing it so that it can be interruptible and resumable. Otherwise it will never complete.

How many simultaneous downloads make sense on iOS

I have an iOS app which synchronizes a certain number of assets at startup. I'm using AFNetworking and set up an NSOperationQueue to handle all of the downloads. I was wondering, how many simultaneous downloads make sense. Is there a limit where network performance will drop if I have to many at the same time? At the moment I'm doing max 5 downloads at a time.
This depends on several factors:
What is the network speed and latency?
What is the data size of the requests and responses?
How long does processing a request take on the server?
How long does processing a response take on the client?
How many parallel requests can the server fulfill efficiently?
How many users will make requests at the same time?
What is the minimal speed and memory size of the target device?
For small and medium sized applications, the limiting factor is usually the device's network latency, but that might not be the case in your situation. In the end, you'll have to test and figure out the most efficient compromise. 5 is a good number to start with.
You might want to set the number of concurrent downloads by the available network connection (WLAN or 3G or even slower...).
The beauty of using NSOperationQueues is that they are closely tied into the underlying OS (iOS or OSX). The queue decides how many operations to run based on many factors, including free memory, load on the system, etc.
You should not try to second guess the system and throttle yourself. Queue as many operations as you have and let the OS deal with it. I have an iPhone app that adds hundreds of operations in the queue when it has to fetch images of varying sizes etc. Works great, UI is not blocked, etc.
EDIT: well, it seems that when doing NSURLConnections and similar network connections, NSOperationQueue is NOT really keyed in to network usage. I asked on the Apple internal forums this summer, and in the end was told by Quinn "The Eskimo" (Apple network guru) to use a limit of something like 4. So this post is correct in the sense of pure processing power - NSOperationQueue will do the right thing - but when it comes to network ops you need to set a limit.
Depends on your hardware mostly I would say. Best way to address this is to test it with multiple cases with multiple trials. Try to diversify the hardware you test on as much as possible (remember do not use the simulator to test this!).
There actually is a constant the SDK provides that varies depending on various constraints. I would recommend you look into using it.
Regarding this question, I've done some tests on a Ipad2 IOS6.0. I've created a little app that performs an HTTP-GET request to a webserver. This webserver will provide data for 60 seconds ( this to get a meaningfull result, will change this to 10 min later in my tests ).
For one HTTP-GET request it works very good. Then I tried to perform several HTTP-request at the same time and see how many and how fast I can download over a WIFI connection of the IPad
I made 2 versions. 1 version using NSOperations and 1 version using NSThread an Synchron HTTP-GET request. In short, I always get a TimeOut for my 6th request. ( The tcp-syn doesn't get to my HTTP-Server ).
Extra info:
NSThead-implementation:
Simply make a for loop and create a Thread. This will perform a synchronized HTTP requests.
There I observe that my 6th request times out after 20 seconds. If I set the Timeout to 80 seconds, I clearly see that after the end of my first http-request ( after 60 seconds ) my 6th request is launched...
NSOperation-implementation:
Create a Queue and set the maxConcurrentOperations to 12. Add 12 http-request Operations to the queue. Here as well I notice that the 6th request gets a -1001 error code ( meaning: timout ). and I see no tcp-syn of the 6th request.

Resources