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
Typically, 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/animations, 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 – Add two call-back functions to your page to monitor progress and gather the final results
function log(fps){
// Do some stuff here with current FPS
}
function end(minfps,avgfps,maxfps){
// Do some other stuff here with min, max and avg fps
}
3 – In your page initialization code, instantiate an FPSMeter object, providing the call-backs as parameters
fpsMeter = new FPSMeter(log,end);
4 – Run the FPS meter for n seconds
fpsMeter.run(n);
Hello!
This library looks quite promising. Thank you for it.
It must be a missunderstanding on my part, but the avgfps value seems a bit off.
Would you ellaborate on why did you use avgFPS = Math.round((avgFPS-worstFPS-bestFPS)/(this.fpsValues.length-2)); to calculate it? (in some cases)
Most probably you have some good reasons what i can’t grasp yet, so your advice and reasoning would be highly appreciated.
thank you
Comment by Krisztian Gergely — November 10, 2011 @ 10:18 am
Hi Krisztian, and thank you for the feedback. To calculate the average FPS, I accumulate all measures, remove the best and the worst and divide by the number of measures minus two. The javascript code is a bit confusing, as I use the same avgFPS variable to accumulate the measures and calculate the final result. It would have been more readable if I had used a ‘sumFPS’ variable for the accumulation, I guess …
Comment by David Corvoysier — November 10, 2011 @ 11:46 am
Thank you for your quick answer, now I understand.
The original issue of why I was sniffing around the code was also fortunately solved.
As I previously said the avgfps looked like a bit off. It was because in the documentation above, you label the parameters of end as: minfps,avgfps,maxfps, but later on you call the callback with avgFPS,worstFPS,bestFPS. If you could clean up this confusion, either in the documentation or in the code, that would be really helpful.
And again thank you for this library, and your time for answering me, and resolving this issue.
Comment by Krisztian Gergely — November 11, 2011 @ 9:18 am