GPU Composited CSS and browser-perf

I was at the Velocity Conference 2014, Santa Clara, speaking about "Automating Website Performance Measuring and adding it to continuous integration". The slides are available here.

Just before my presentation, I had the chance to catch up with Ariya Hidayat and we spoke about his work on GPU Composited CSS.His article talks about how CSS computations can be offloaded to the GPU and how over-doing it would simply exhaust the GPU.

He suggested that it would be interesting to see how browser-perf worked on his Codepen examples. It is clear from the developer timline tools (as described in Ariya's article) that work is transferred to the GPU. The cooler part would be trying to see if picking up this information can be automated.

I wrote a quick script before the presentation to demonstrate this, but the projectors did not agree with my laptop, and I just had to show static slides. Here are the details of my experiments.

Experiment 1: Impact of number of color changing rectangles

This codepen page shows different number of rectangles on the screen, each changing color using keyframes. browser-perf recorded the metrics for 1, 10 and 100 boxes. Here is the comparison for each case

Metric One Ten Hundred Units
CompositeLayers 20.00 58.99 171.00 ms
CompositeLayers_count 90 113 136 count
Layers 7 17 106 count
Paint 0.00 2.72 277.99 ms
Paint_count 1 20 7332 count

As seen from the table, the number of layers and composite layers increases with the number of rectangles on the screen. The number of times paint is called and the time per paint also increases.

Experiment 2: Changing Color vs Changing Opacity

As seen from the experiments above, changing the color causes the GPU to redraw the texture. A simpler way to simulate the same effect would be to use two  rectangles and slowly show one while hiding the other. With their opacity changing over time, they approximately show the same effect.
Metric Color Change Opacity Change Unit
CompositeLayers 33.99 10.00 ms
Paint_count 51 5 count
Layers 6 2 count
The same page was used for changing colors, while this codepen was used to try changing the opacity.
The numbers also confirm that the number of times paint happened is much lower when the opacity changes. Similarly, the number of layers and composite layers in case of changing the color is much higher.

To summarize, certain properties like background color, borders, shape, etc make the GPU redraw the rectangle and should be avoided when trying to achieve a smooth web page.

Here is the full gist with all the data and the code to re-run the experiments. Have interesting rendering performance examples and want to measure the metrics for them? Ping me and I would love to help you run browser-perf on your examples.

Perfslides - demo app to show that browser-perf works

Performance Graphs for a website generated using browserperf

I have been working on browser-perf for quite some time now. With browser-perf and perfjankie, front end performance monitoring can be easily added to any continuous integration system. These tools make a lot of interesting metrics available. I always wanted to a project that demonstrates how this information can be actionable and associated to code that can be fixed to improve performance.

Perfslides is a project to show how changes in code across individual commits can impact smoothness and jank of a web page. It also doubles up as a slide deck that was used at conferences where I spoke about these tools.
The project has a simple, long and scrollable webpage on which the performance tests are run. The perf branch has five commits which are compared. Each commit is isolated in functionality to demonstrate a problem with jank or how it was fixed. These code snippets are from real world projects.
A graph over these five commits clearly shows the relation between the changed code and their impact of performance.

The Commits
The five commits are as follows
  1. The first commit is a very basic version of the site with minimal bootstrap styling. The site has unscaled images from the slides and the site. 
  2. The second commit is a styled version of the page, with parts related to the presentation hidden. This translates to hiding many large pictures that were used for the slide deck. Other styles included aligning the text, resizing images, etc. 
  3. The third commit mocks a feature that introduces performance regressions. This code has a scroll handler that tries to position a bookmark indicating the amount scrolled. Amongst other things, it also tries to save this information in a cookie to reload the page at the same position it was scrolled to. 
  4. This commit fixes the performance regression by delegating all the expensive work to a requestAnimationFrame call, using CSS transforms and caching all jQuery elements.
  5. The final commit shows the impact of third party Javascript to a file. In this case, social sharing buttons and a comments form was added to the site. 
Integrating performance tests was as simple as adding a grunt task from perfjankie. Running grunt perf starts up the web server, connects to local selenium, runs the tests and saves all the data to a local database. This data is also replicated to a cloudant server and shows the impact of each commit on the metric.

The Metrics
Some noticeable and interesting changes to the metrics are
  • When adding a scroll handler, the mean frame time improves when work is delegated to requestAnimationFrame.
  • The addition of CSS3 transforms in commit 4 is shown by the increase in Layers metric
  • The average painted area is also different
  • Javascript execution time and navigation metrics increase when third party code was added to the site.
  • The main difference between commit 1 and 2 is resized images. Looking at the DecodeImage and ResizeImage clearly indicates this. 

Testing Cordova
The built folder was also copied to the www folder in a cordova project and similar performance tests were run. The results were very similar.

Using it for your sites
Checking the developer tools for performance regressions after every deploy is very hard. Using tools like browserperf and perfjankie make tracking regressions simple. You could simple add a grunt task as shown in this project, connect to hosted browsers on saucelabs and save the data on cloudant. Alternatively, you could also try out this entire setup by signing up for perfmonkey.com, and sending a CURL request every time a new version of the site is deployed. Perfmonkey.com is a hosted service that does all this for you.

Follow the projects on github or watch out this space for more updates.