iOS presentRenderBuffer blocking - ios

Setup:
CADisplayLink on main thread, configured to fire every interval
iOS 10.2
OpenGLES 2.0
iPhone 6
.
-(void)callbackFromCADisplayLink:(CADisplayLink *)dl
{
u64 tStart = high_res_clock_now();
<Process input, advance game world, prepare graphics commands>
// Frame processed
u64 prePresentElapsed = high_res_clock_now() - tStart;
[myEAGLContext presentRenderbuffer:GL_RENDERBUFFER];
// Graphics commands submitted
u64 postPresentElapsed = high_res_clock_now() - tStart;
}
What I'm finding is:
prePresentElapsed is consistently in the 0.5-2.5ms range.
There are essentially 2 graphics modes:
"Fast mode": where postPresentElapsed is consistently in 1.5-4ms range
"Slow mode": where postPresentElapsed is consistently hovering at 16ms
The system starts in "Fast mode", but degenerates to "Slow mode" seemingly randomly (doesn't appear to be associated with a large frame spike), and then stays in "Slow mode" until the app is put into inactive/background state, then back into active state.
Clearly, it appears presentRenderbuffer is blocking due to downstream effects of vsync.
Questions:
What causes the switch between modes?
How can I reliably stay in "Fast mode"

iOS is very active in modifying the clock speed of the CPU and GPU. As far as the OS is concerned, the ideal state is for your app to run consistently at 60fps with the lowest possible clock speed (which sounds like what is happening in your slow mode)
When your app launches, the clock speed starts out high, once things have had a little while to settle down, the OS gets the measure of your app and slows the clock speed down as much as it possibly can without affecting the user experience. It does this to save the users battery and keep the device cool.
It's quite frustrating, because there's no way to disable, control or even monitor this behaviour as far as I'm aware, so it makes performance measurement a lot harder. It also means that you're bound to miss the odd frame when the app has a busy frame, because the clock speed management won't be able to raise the clock speed until it's too late.

Related

In iOS, How many times does RunLoop cycle in one second

In iOS, How many times does RunLoop cycle in one second?
Is it the same as the screen refresh rate, 60 times a second?
No, the run loop frequency is not the same as the screen refresh rate. (It generally exceeds the potential screen refresh rates unless you block the thread.)
When we need to coordinate something with the screen refresh process, we generally use a CADisplayLink, which not only runs with the desired frequency, but also maximizes its timing within the screen refresh cycle.
Note, screen refresh rates can vary from device to device, and, on new devices, they can even vary depending upon the needs of a particular task running on a particular device (faster when you need better performance, slower when not needed and you want to enjoy more energy efficiency). See Optimizing ProMotion Refresh Rates for iPhone 13 Pro and iPad Pro.

6S+ GPU traces: cannot account for huge MS difference

FAST trace
SLOW trace
These two traces were captured a couple of minutes apart on an iPhone 6S+ on a more or less static menu. One completes in around 8ms, the other in around 14ms. The game will sit quite happily at 7-8ms render time and then, for no apparent reason, rise up to 14ms frame time for a while.
Bafflingly, individual draw calls take almost twice as long in the 'slow' trace as in the 'fast' trace, though I can see no difference between them. The first draw call in particular is noteworthy: a screen-filling quad with a very simple shader that completes in either 1.x ms or 2.x ms, with (so far as I can tell) identical GL settings in force both times.
I can load both traces into xcode and hit 'analyse', and the results are totally reproducible: the slow trace is always slow, and the fast trace is always fast, and I can't see what's different!
Notes: Yes, there are some redundant GL calls generated by our engine. They're the same in both traces, so they're not the focus of this investigation. And yes, the first two calls are a terrible way to achieve a full-screen fill; I've already talked to the designers :) Again: not the focus here because the question is why are those calls taking twice as long in one trace compared to the other.
The game will sit quite happily at 7-8ms render time and then, for no
apparent reason, rise up to 14ms frame time for a while.
I think what you're seeing here is the dynamic energy saving on the device. If you're comfortably hitting your framerate target, then the OS can reduce the clock speed of the CPU/GPU to reduce energy consumption and heat generation.
Unfortunately, this behaviour makes it very difficult to profile performance. I'm not aware of any way to disable this for performance measuring, or to view the current CPU/GPU clock speed (or the number of cores that have been shut down) to confirm the cause of confusing measurements.
I've not looked at your traces, but it's possible that the one you think is slower is actually marginally faster, and comes just under the threshold where the OS decides to half the clock speeds to save energy.

Core Animation profiling: When an app is idle, should it be 0fps of 60fps?

I've been trying to optimize scrolling of my UICollectionView, and the Core Animation profiler has me puzzled...
When the app is idle (no scrolling or interaction in anyway) I'm averaging around 59-60 fps, but occasionally it will drop down to 7 or 12 fps:
Is this expected behavior? Because I'm not interacting with the app when this drop happens I don't visually see anything, but I'm curious if this is something I should be troubleshooting.
Other times when profiling core animation bottlenecks I've seen fps drop down to 0 fps when idle/not interacting with the app.
The app isn't crash or freezing, so is this some sort of bug in Instruments? (I'd expect consistently to be 0fps or close to 60fps when nothing is happening in the app).
Update:
Here's an example of the FPS graph after running the profiler a few minutes later (I'd tried turning on rasterization for a type of view, but then reverted back to not rasterizing, so although the project was rebuilt, the codebase is the same):
Here I'm getting between 32 and 55 fps when interacting with the app, and dropping down to 0 fps when idle.
From my subjective perspective I'm not noticing anything major between what I'm seeing between these two examples, but from Xcode's perspective I'm seeing two different stories.
Does anyone know what's happening here?

ios "smart" location tracker and battery drain

I'm creating an activity tracker similar to the "Moves" app that seeks to track steps, distance, calories and active time.
For Iphone5s+ devices, I am using the built in M7 chip to determine Steps, and then making estimates at the rest from that. For M7 devices I never use GPS. There is basically no battery drain and the interpolated numbers are reasonable enough for the need. This gets walking/running data reasonably enough.
However to support Iphone5 and Iphone4 at least, I need to use GPS to get location and then interpolate steps and calories from the distance. I'm running into significant battery drain issues (somewhat expected), and am seeking advice on how to minimize this. I'm also using the accelerometer in addition to speed to help make an educated guess on activity type (walking,running,biking,transport)
Some things I've tried for GPS optimization:
Deferred Updates: The Iphone5 and a minimum version of IOS supports this. The code to do this is straight forward, however whether the device actually uses it is questionable. I've only seen it work on 1 out of 4 devices, where it does regularly. 3 other devices have never deferred updates from the same code. Another user suggested other apps prevent the device from sleeping, including when I had "Moves" also installed. This thus hasn't helped much beyond theory.
Reduce Accuracy: reduce the accuracy of continuous location polling. I started at High, but reduced to 10m, then hundreds of meters, etc. This doesn't seem to help and polling still seems to occur at a regular interval anyway.
startMonitoringSignificantLocationChanges: In order to reduce endless gps polling when the user may not be moving for hours at a time (especially at night), I switched from continuous polling to significant changes only after the device stopped moving for an arbitrary 2 minutes. I then re enable continuous tracking after any significant location update. This works pretty much as expected-- if it stops tracking then battery drain slows, and when it resumes continuously, battery drain resumes. Further, if a user starts walking, there is no guarantee of a significant motion event for some time. This is very poor for accuracy. Sometimes it doesn't seem to resume at all.
I've been relatively impressed that the "Moves" app, among others is able to track location so well with respectable battery drain. It can go most of a day until needing a charge. With my code, users have reported full battery drain in a couple of hours.
What kind of optimizations could be used to improve this but still maintain a reasonable accuracy in tracking movement?
PROGRESS UPDATE:
startMonitoringSignificantLocationChanges. I set this up with a timer that switches to significant monitoring after 2 minutes of inactivity (not moving). Normal location tracking is then resumed again on any significant change, or when the app becomes active from reopening. This seems to work well. My phone still goes from 100% to 10% in 8 hours overnight of sitting around. It is an old iphone with some battery troubles, but normally it might just lose 30-40% uncharged overnight with no apps running. I need to test more, but startMonitoringSignificantLocationChanges still seems to use some battery.
Further, startMonitoringSignificantLocationChanges has some expected accuracy issues in terms of when it restarts the app. In rural setting, it can go several kilometers before restarting. This could be okay for a long drive, but if I want to catch a 30 minute walk, it may miss that entirely. In urban setting it seems to kick in within 2-3 blocks of movement, which is reasonable.
Even if I used continuous location tracking that stopped+started on a timer to check for movement, I'd still likely have worst case of a minute of lag between restarts before resuming continuous logging.
PROGRESS UPDATE 2:
Significant change updates described above have a fatal flaw for me: they don't always start fast enough. Sometimes it takes 1-2 miles it seems!
As an a better approach, I've tried keeping continuous location updates on, but toggling the "desiredAccuracy" property from high to low accuracy when the device is not moving. This should essentially turn the GPS receiver off during inactivity. I've been experimenting between 100meter and 1km accuracy for inactivity with promising results. It does seem to use slightly more batter than only using significant change monitoring, but it seems more responsive as well.
Nothing of your above proposed solutions works.
You need GPS, and that is enabled if you speficiy full precision (CLLocationAcuracyBest).
if I remeber correctly there is a difference betwween CLLocationAcuracyBest and CLLocationAcuracyBestForNavigation that way that the latter uses additonaly the acceleration sensor, which in sum uses more battery.
There is no half battery GPS mode!
A GPS chip is enabled or not.
For distance counting you need GPS, cell Tower and Wlan locations will not work.
And only the cell tower an Wlan locationg can save battery.
On Iphone4 such an full precision GPS App (e.g my) lasts about 8 hours untill the battery is low.
8 hours are enough, if the user has a benefit of the app.

Interpreting downward spikes in Time Profiler

I'd appreciate some help on how I should interpret some results I get from Time Profiler and Activity Monitor. I couldn't find anything on this on the site, probably because the question is rather specific. However, I imagine I'm not the only one not sure what to read into the spikes they get on the Time Profiler.
I'm trying to figure out why my game is having regular hiccups on the iPhone 4. I'm trying to run it at 60 FPS, so I know it's tricky on such an old device, but I know some other games manage that fine. I'm using Unity, but this is a more general question about interpreting Instruments results. I don't have enough reputation to post images, and I can only post two links, so I can't post everything I'd like.
Here is what I get running my game on Time Profiler:
Screenshot of Time Profiler running my game
As far as I understand (but please correct me if I'm wrong), this graph is showing how much CPU my game uses during each sample the Time Profiler takes (I've set the samples to be taken once per millisecond). As you can see, there are frequent downward spikes in that graph, which (based on looking at the game itself as it plays) coincide with the hiccups in the game.
Additionally, the spikes are more common while I touch the device, especially if I move my finger on it continuously (which is what I did while playing our game above). (I couldn't make a comparable non-touching version because my game requires touching, but see below for a comparison.)
What confuses me here is that the spikes are downward: If my code was inefficient, doing too many calculations on some frames, I'd expect to see upward spikes, now downward. So here are the theories I've managed to come up with:
1) The downward spikes represent something else stealing CPU time (like, a background task, or the CPU's speed itself varying, or something). Because less time is available for my processing, I get hiccups, and it also shows as my app using less CPU.
2) My code is in fact inefficient, causing spikes every now and then. Because the processing takes isn't finished in one frame, it continues onto the next, but only needs a little extra time. That means that on that second frame, it uses less CPU, resulting in a downward spike. (It is my understanding that iOS frames are always equal legnth, say, 1/60 s, and so the third frame cannot start early even if we spent just a little extra time on the second.)
3) This is just a sampling problem, caused by the fact that the sampling frequency is 1ms while the frame length is about 16ms.
Both theories would make sense to me, and would also explain why our game has hiccups but some lighter games don't. 1) Lighter games would not suffer so badly from CPU stolen, because they don't need that much CPU to begin with. 2) Lighter games don't have as many spikes of their own.
However, some other tests seem to go against each of these theories:
1) If frames always get stolen like this, I'd expect similar spikes to appear on other games too. However, testing with another game (from the App Store, also using Unity), I don't get them (I had an image to show that but unfortunately I cannot post it).
Note: This game has lots of hiccups while running in the Time Profiler as well, so hiccups don't seem to always mean downward spikes.
2) To test the hypothesis that my app is simply spiking, I wrote a program (again in Unity) that wastes a consistent amount of milliseconds per frame (by running a loop until the specified time has passed according to the system clock). Here's what I get on Time Profiler when I make it waste 8ms per frame:
Screenshot of Time Profiler running my time waster app
As you can see, the downward spikes are still there, even though the app really shouldn't be able to cause spikes. (You can also see the effect of touching here, as I didn't touch it for the first half of the visible graph, and touched it continuously for the second.)
3) If this was due to unsync between the framerate and the sampling, I'd expect there to be a lot more oscillation there. Surely, my app would use 100% of the milliseconds until it's done with a frame, then drop to zero?
So I'm pretty confused about what to make of this. I'd appreciate any insight you can provide into this, and if you can tell me how to fix it, all the better!
Best regards,
Tommi Horttana
Have you tried unity's profiler? Does it show simillar results? Note that unity3d has two profilers on ios:
editor profiler - pro only (but there is a 30 day trial)
internal profiler - you have to enable it in xcode project's source
Look at http://docs.unity3d.com/Manual/MobileProfiling.html, maybe something will hint you.
If i had to guess, I'd check one of the most common source timing hickups - the mono garbage collector.
Try running it yourself in a set frequency (like every 250ms) and see if there is a difference in the pattern:
System.GC.Collect();

Resources