SKView and CADisplayLink combination for dropped frame detection affects animation performance in iOS 9

Originator:connerk
Number:rdar://26907286 Date Originated:20 June 2016
Status:Open Resolved:
Product:iOS SDK Product Version:9.x
Classification:Performance Reproducible:Always
 
Summary:
I built a performance tool called KMCGeigerCounter. You build it into your app and enable it, and it plays a Geiger counter click when your animation drops a frame. This is useful for detecting small framerate drops such as Auto Layout stutters when scrolling in a table view: You can't see the difference between 58 fps and 60 fps, but you can hear it.

There are two causes of dropped frames on iOS that I know of:

1. Your main thread fails to prepare the layer hierarchy in time
2. Your layer hierarchy fails to finish drawing in time

Using CADisplayLink and measuring the intervals between callback calls, I can detect type 1 frame drops. But type 2 frame drops don't interfere with CADisplayLink because layer drawing is done out-of-process. So, my tool includes a 1pt-1pt SKView which must draw out of process, then simulate in-process on the main thread before drawing again. This causes the CADisplayLink event to be delayed by the aug-of-process drawing operation, so that dropped frames can be detected.

On iOS 8, using this measurement technique produces no noticeable effect on the app's regular framerate. On iOS 9, there is a severe performance degradation. I showed this to a few people at WWDC 2016 labs (notably REDACTED at Core Animation lab). The consensus was that on iOS 9 there should not have been this performance penalty.

After WWDC, I tried iOS 10. Now the tool only detects the type 1 frame drops and not type 2.

Steps to Reproduce:
1. Clone https://github.com/kconner/KMCGeigerCounter
2. Check out commit 26e6cbbe0798c64a66c2c4bd52a30808eed29210, which is the ios9 branch at this time of writing.
3. For each iOS version among 8, 9, and 10, build and run on a device.
4. Observe the framerate when scrolling in the application's first tab, which is meant to produce type 2 frame drops.
5. Observe that with the speaker on, dropped frames are accompanied by a click.
6. Observe that on iOS 10, dropped frames are not detected except when rotating the device (type 1 frame drops).
7. In KMCAppDelegate, disable the tool by setting [KMCGeigerCounter sharedGeigerCounter].enabled = NO, then build and run on all three devices again.
8. Observe that iOS 8 and 10 perform similarly regardless of whether the tool is enabled.
9. Observe that iOS 9 performs significantly better with the tool disabled.

Expected Results:
On each OS version, the application should draw at a similar framerate regardless of whether the tool is enabled or disabled.
iOS 10 should be able to detect type 2 frame drops.

Actual Results:
iOS 9 performs worse with the tool enabled than with it disabled.
iOS 8 and 10 perform the same with the tool enabled and disabled, as expected.
iOS 8 and 9 can detect type 1 and 2 frame drops. iOS 10 can only detect type 1.

Version:
iPhone 4s: iOS 8.3. iPhone 6s: iOS 9.3, then iOS 10 beta 1. Xcode 7.3.1.

Notes:
On iOS 9, I tried a lot of different things, but none were fruitful. From my code comments:

// Maybe if I use only the SKView and not the CADisplayLink?
// No, that doesn't help. The SKView alone is causing the drawing latency. The CADisplayLink does not interfere.
// SceneKit doens't exist before iOS 8, so I'd prefer not to rely on it.
// A GLKViewController works on the default run loop, so it doesn't get updates during core animation scrolling.
// Using a custom view with -drawRect: or -displayLayer:, callbacks happen just as often as CADisplayLink.
// I need a new way to accurately detect when a frame is drawn to the screen without affecting the framerate.

On iOS 10, my hack appears not to work. I am interested in any way to detect dropped frames of both types on iOS 9 and 10. E.g. I do this with -layerWillDraw?

I understand you can't recommend private API usage, but barring a solution, that is where I would turn next. This tool is not meant to ship with a product anyway.

Configuration:
iPhone 4s, iPhone 6s.

Comments


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!