Effectively measuring browser framerate using CSS

27 Jun 2011 by David Corvoysier

Most browsers now provides features allowing the web developers to design animated user interfaces that were before only available through proprietary plugins such as Flash or Silverlight.

Namely, CSS 3 transformations, transitions and animations, HTML 5 canvas or WebGL are the new kids on the block (for those wondering: yes, I was a teen in the 80s), and have received a lot of attention since a certain mr jobs claimed that no flash plugin would ever make it to his products.

So: what happens when a browser feature becomes widely implemented and popular ? Competition between implementations, of course !

The trouble is that it may be relatively easy to evaluate javascript performance (although one may argue that event javascript benchmarks are biased), but it is a bit more complicated to evaluate actual browser framerate.

How browser rendering is implemented

Most of the time, and although they may use background processes to perform specific asynchronous tasks (such as resource downloads for instance), web browsers do render each web page in a single thread, splitting the CPU time between javascript and rendering tasks.

Typically, on every frame, the browser executes some javascript functions piled in a javascript code queue (with a priority given on timed functions) for a given amount of time (typically 50ms), and then checks whether the page needs to be refreshed or not. If the page needs to be refreshed (either because, the DOM itself has been modified or because a new CSS rule modifies the layout, or for many other reasons ...), it calculates the new page layout, isolates the portion of the page that it needs to refresh (sometimes called the "damaged" or "dirty" region), and renders it to its "backing store" (typically an internal buffer where all the drawing stuff occurs). Once done, it pushes the modified frame on screen using whatever mechanism the host operating system provides.

The important thing to note here is that ultimately, the operating system video drivers decide when the frame is actually pushed to screen: this means that trying to achieve a framerate that exceeds the video output synchronisation rate (typically 60Hz) is useless. As a matter fo fact, most browsers have a "framerate cap" hard-coded somewhere to avoid unecessary rendering operations (Chrome provides an option to remove this cap in about:flags).

Why javascript alone can't be used to calculate FPS

Since actual frame rendering is not directly related to javascript based DOM or CSS modifications, relying solely on javascript loops to measure an animation framerate will most likely lead to very optimistic results (see for instance the Bubblemark javascript based benchmark that gives awesome results even when the actual rendering looks completely frozen).

Even worse, with CSS triggered animations, there is no way for the javascript to be notified of a new frame being rendered (actually, the whole point of this new CSS stuff is to avoid the javascript overhead).

How CSS can be used to calculate FPS (with a little javascript also)

Having thought a little about this issue, I came up with the idea of using CSS itself to evaluate the actual rendering framerate of a page.

The principle is quite simple: - insert a very simple CSS animated item in a page, - calculate the computed position of this item at regular intervals, - every second that has elapsed, count the number of different positions occupied by the item.

Pretty dumb, uh ? Well, maybe, but it gives surprisingly accurate results, actually ...

Obviously, this only works on browser supporting CSS transitions, but these are actually the implementations we want to evaluate, so this isn't really an issue.

The fpsmeter script

I have developed a little script that does just what I've described in the previous paragraph.

Get the script Here.

Here is a brief HowTo:

1 - Include the fpsmeter script to your page
<script type="text/javascript" src="<path_to>/fpsmeter.js"></script>
2 - After the page has been loaded, a new FPSMeter window member should be available:
    alert("This test page doesn't seem to include FPSMeter: aborting"); 
3 - Register a call-back function to monitor fps
function log(fps){
// Do some stuff here with current FPS

4 - Start the FPS analysis

5 - Perform the animation you want to evaluate

6 - When done, stop the FPS analysis (optional)
comments powered by Disqus