Performance Tuning on Older iOS Devices

August 12, 2011

The hardware capabilities of iOS devices have improved dramatically in the two most recent generations, which has helped fuel the growth of increasingly complex apps featuring augmented reality and photorealistic gaming. While such advances are great for the iOS platform, it is important for developers to consider older generations of iPhones and iPod touches that are still a significant portion of the installed base. This post will cover some important perfomance tweaks to improve the user experience on these slower devices.

Jerky scrolling and choppy animations are the most obvious symptoms of a performance problem on older hardware. They are commonly caused by overuse of transparency and alpha blending, which are very expensive CPU and GPU operations. It's also quite possible that an app might be blending many layers under the hood without the developer's knowledge. Using Instruments, we can set various kernel flags to reveal intentional or inadvertent blended views.

Color Blended Layers

Open Instruments and choose the Core Animation template located under iOS / Graphics. First, click in the Core Animation instrument's timeline to reveal the bottom pane and find the section labeled "Debug Options". Check the "Color Blended Layers" box, which will show a red overlay over layers that were blended and a green overlay over layers drawn without blending.

Screenshot of an iOS app with and without Color Blended Layers enabled

This image shows a screenshot of an app with and without the blended layers overlay enabled. You'll quickly notice that every UILabel in the table header and in each cell has a red overlay. The labels have a clear backgroundColor, which forces the renderer to blend the transparent pixels with the cell's own background color to produce the final image drawn to the screen. Because the cell background is a flat color, we can save this unnecessary calculation by setting the label to be opaque and the backgroundColor to the same color as the cell background. The updated labels will draw the exact same pixels to the screen with reduced processing time.

This speed up occurs for each label we fix, which in this view is 39 total labels (9 in the header and 5 per cell). On a 3rd-generation iPod touch, scrolling performance increased from 18.3 fps to 27.6 fps, a 50.8% improvement.

Color Misaligned Images

Another source of unintentional blending is misaligned views that force the renderer to anti-alias before they are drawn. In this context, "misaligned" means that the requested display point does not map directly to a screen pixel (for example, it could be between two pixels), and therefore must be drawn to two neighboring pixels and anti-aliased to give the illusion that it was drawn "between" the them. This almost always happens when a view's frame is computed (rather than specified in Interface Builder) because a CGRect's X coordinate, Y coordinate, width, and height are CGFloats and therefore allow fractional values. For example, a 100.8px by 50.1px box centered at (200.5, 35.5) is a valid frame and the OS will try to render it the best it can manage. The additional interpolation and anti-aliasing overhead required for just a single pixel is enough to severely hurt performance on older hardware.

Screenshot of an iOS app with and without Color Misaligned Images enabled

Under "Debug Options", check the "Color Misaligned Images" checkbox, which will show a magenta overlay over layers that are positioned between pixels. This image shows a screenshot of an app with and without the misaligned images overlay enabled. Each group in the table view has a custom header that is positioned in code, and it changes based on the width of the label text. All it takes to fix the misalignment is to call either floorf() or ceilf() (either one will work, just be consistent) on every computed value of a frame. You can also use CGRectIntegral() for frames, which always rounds up. The fixed views will render faster and often appear less blurry. On a 3rd-generation iPod touch, scrolling performance increased from 32 fps to 43 fps, a modest 34.3% improvement.

These two techniques allow developers to easily find and remove unnecessary graphics overhead and improve the user experience on older iOS devices. Even on newer devices where the user won't necessarily visually perceive improved performance, a reduction in overhead will improve battery life after extended use.