How elegant code can hurt HTML5 performance

Elegant code can lead to cleaner, precise steps. But it can also lead to application performance bottlenecks, argues Mozilla's Andreas Gal.

Developers often focus on creating elegant code that is short and straightforward. However, this can kill browser performance when it fails to respect the way browsers actually render applications, said Andreas Gal, Mozilla CTO, at the Fluent Conference in San Francisco.

There are differences in the ways that browsers execute similar looking visual effects in HTML5 code, which can lead to dramatically different application performance. Gal advocates that developers take the time to understand the types of processes modern browsers like Firefox execute to translate HTML5 and JavaScript application code in graphical effects.

This is important because modern devices including smartphones and PCs generate user interface (UI) animations using a stream of images. A fluid graphic experience is presented at 60 frames per second (FPS), which corresponds to about 16 milliseconds (ms). Every time the browser needs to present a new image, the application needs to be ready with the updated image frame. If delays in the application cause it to miss one frame, people will notice, and if two frames are missed, users will complain.

Serial rendering in a parallel world

The problem is that the rendering engine in the browser is serial, whereas much of the application logic is processed in parallel. All of the actions the browser performs, like running JavaScript, have to happen in a serial fashion. This means there are a number of ways to miss the 16 ms target required for a smooth application experience. Endless loops can pause execution significantly. Parsing a lot of JSON code can inject pauses. In one demonstration Gal showed how subtle differences in code for the same effect can mean the difference between a 5 ms and 331 ms execution time.

Use absolute positioning for layout

The principle purpose of layout functions is to present the boxes on the screen, but it can be tricky when the positions of the boxes are related to each other. When boxes do get moved around, they can cause other boxes to change positions and might require the application to recalculate the size of other boxes. Using absolute positioning rather than relative positioning makes it easier for the application to proceed smoothly without having to update boxes that are not shown on the screen.

Favor translation and alpha compositing

It is also important for developers to understand the impact of different graphics manipulation techniques. Mobile and desktop browsers are good at translation and alpha compositing. The device's GPU can often help accelerate this process. But changing the scale of elements rendered onto a screen can lead to performance delays. As a result, most CPUs cannot render scaled images at 60 FPS smoothly.

Avoid animated GIFs

Animated GIFs are growing in popularity on many sites owing to their small file size. However, they should be avoided when possible, Gal argued. Use video for animations rather than GIFs to achieve good performance. When a browser tries to animate a GIF, it uses the change in images to render the objects. Although the files can be small, rendering them taxes CPUs and memory. For example, a 200 KB animated GIF can require gigabytes of internal memory to render. Video formats are much easier to render, can better leverage the GPU, and make it easier to throw out frame data after it is presented.

Avoid stroking images

JavaScript makes it possible to create images and animations using strokes, but this should be avoided too, Gal said. Trying to interpolate points during the stroking process can tax the devices' CPU.

Line up image elements with pixels

It is also important to ensure that image elements align with device pixels. When image elements are not aligned, the browser will try to represent that as closely as possible. This can become particularly demanding when the user scrolls and the browser is trying to recalculate how to render the image element across pixels. It is easy to get this wrong when using canvas functions to render elements.

Avoid reading back from the GPU

Developers need to understand how the GPUs are architected to process image data. Don't read back pixels, Gal said. Most GPUs have a separate memory system from the main CPU. The CPU sends blocks of graphics to the GPU. The limited interconnect between the GPU back to the CPU can create a bottleneck when the application tries to move data back before rendering.

Understand layer optimizations

Another good practice is to understand how the browser splits up an image into layers. The idea of layers is to allow GPU cores more manageable chunks of graphics to work with. It is easy to do translation and alpha compositing on the GPU. The browser uses heuristics to infer good boundaries, which can create some artifacts. Therefore use tooling to make sense of how the browser splits up images.

More on this topic:

Why HTML5 implementations should happen now

Mobile development buoyed by JavaScript, HTML5 trend

Gal observed that there are many ways to kill the performance of HTML5 applications, and these tips are merely a starting point for what can go wrong. When problems do occur, it's a good idea to run the code through a profiler to help identify the specific application logic creating the bottlenecks. The Octane 2.0 benchmark tool makes it possible to assess where these various pauses occur, and works better for measuring code changes on user experience than older benchmark tools did. The JIT Coach component of Mozilla DevTools looks at the performance-critical code based on what the JIT compiler is doing. It is important to use code profilers rather than look at code directly in order to understand performance impact, Gal said.

Has elegant code created application performance bottlenecks for your enterprise? If so, let us know how you have managed this setback.

Dig Deeper on Java Development Tools

App Architecture
Software Quality
Cloud Computing