On accurately measuring fps6
If you look for a quick solution, I have bad news: It’s not possible. Not even close. Well, in the browser at least.
For many subsequent years, smart web developers have tried and failed to produce accurate ways to measure something that comes close to displayed frames per second on websites. Something that’d been so vital to the gaming industry for decades can’t be that hard to measure, right?
In the web world, fps map closest to redraws. Redraws (or repaints) happen when anything on screen needs to visually change (if the layout changes as well, an additional reflow/relayout will be done). Many implementations tried to address the same problem:
- running intervals at ~16ms (60fps) and check how long they actually run to produce a number
- changing the width of a DOM element and read out the offsetWidth to see if the new width has been applied
- Internal browser debug tools (namely Chrome and WebKit)
- the Mozilla-only MozAfterPaint event
- requestAnimationFrame
I have tracked all of them down for you so you don’t have to try them out only to find out later that you’ve been tricked. Yes, none of them actually work. Yes, it’s a bloody nightmare.
Running intervals is never reliable – it just tells you that the JS execution is taking time, or sometimes not even that – many browsers throttle intervals artificially in some cases. It gives you no information whatsoever about painting. Changing the width of an element and reading back the offset values is better, as the numbers are smaller (smaller = more realistic), but too small – you want redraws only, not expensive reflows. Internal debug tools, such us the WebKit Debug menu or Chrome’s flags will show an FPS counter but no FPS. Rather, the opposite – Chrome’s FPS counter goes up when lots of stuff on screen happens, and goes to zero when the browser idles. The MozAfterPaint event wasn’t reliable when I tested it many months ago. The same goes for requestAnimationFrame.
I honestly don’t know why requestAnimationFrame is such a let down. It was supposed to be the cure for all our fps needs. Browser vendors told me over and over that this is the number I’ll want. Well, it’s not. I trust my vision more than your API. And I know when the counters are lying. You’re telling me 60fps when I’m clearly seing 20.
Update: I get the feeling that it’s wrong to blame requestAnimationFrame – it’s not even meant to report the number of draws, but rather informs you when you theoretically might be able to draw. I need feedback instead.
Seriously now. Can somebody please fix this?? You’ll be my personal hero for a month and I’ll buy you a nice german beer.
6 Comments
Markus Stange on October 17th, 2011
“Chrome’s FPS counter goes up when lots of stuff on screen happens, and goes to zero when the browser idles”
Huh? What’s wrong with that? I guess I don’t understand what exactly you’re looking for. Maybe you want the number of theoretically possible draws per second, and not only those that have actually been performed?
In Firefox (Nightly), you can get an FPS counter similar to Chrome’s when you’re using OpenGL acceleration and have layers.acceleration.draw-fps set to true.
smfr on October 17th, 2011
You should file a bug if fps computed bvia requestAnimationFrame doesn’t seem to give you the same framerate you’re seeing. Better yet, throw up some content the browser devs can test with.
Paul on October 18th, 2011
@Ariya interesting presentation, thanks for the link!
@Markus: True, possibly those are the actual executed draws. In a controlled game-like environment, you are always executing the draw routine, even if there’s nothing to draw. Sou you’ll want the numbers to say “60″ or whatever if the max when there’s nothing going on.
@smfr: OK. As mentioned on Twitter, it’s really hard to produce a test case if you can’t compare it to anything that works, other than your vision. I’ll try my best. I realized after writing the blog post that I really didn’t give you any help..
Markus Stange on October 19th, 2011
I don’t agree. I think the numbers should reflect what’s actually happening. The fact that browsers only execute the draw routine when necessary is a good thing; behaving like a game would be very wasteful.
In any case, here’s a Firefox extension that shows both potential and actual fps (implemented with requestAnimationFrame): https://github.com/pcwalton/firefox-framerate-monitor/downloads
Paul on October 19th, 2011
@Markus: That’s fine, but then just show me draws, and how long they take, not the inverse (framerate). This makes it way clearer. Thanks for the link!
Ariya on October 17th, 2011
A very specific workaround not mentioned above is to actually use the embedded rendering engine (slide 32-35 in http://www.slideshare.net/ariyahidayat/analyzing-the-performance-of-mobile-web). However, that’s extremely platform and engine dependent.
If finally there is a standard protocol for remote debugging, actual frame rate and other instrumentation information should be passed along. But I agree that in all cases, letting the JavaScript client code knows the speed of the current repainting is really useful.