Measuring Input Lag in Browsers

For games, the time between a key-press and the appropriate action happening on the screen can often decide over virtual life or death.

It is no surprise that game developers go to great length to reduce input lag as much as possible. Guitar Hero for instance even has an option to compensate for lag. One of the biggest time hogs these days seem to be displays, but a poorly written application or game can introduce a lot of lag as well.

The typical path a key-press travels – Keyboard » USB Driver » OS » Application – is bad enough as each of these layer can introduce some lag. Yet, JavaScript games have to go through an additional layer they have no control over: the browser – which in itself may have several layers that introduce lag until a JavaScript callback for a keydown event can be called.

I decided to try and measure this lag for different browsers to see if there's room for improvement. The good news: most browsers do a good job delivering input to JavaScript events as fast as possible. The bad news: Chrome does not.

I build a simple website that draws to a canvas element at 60 frames per second, counts the number of frames and captures input events. I used my camera (a Samsung NX200) to record video at 120 frames per second, then slowed the video down even further to have a close look at the results.

The response time from the command prompt was used as a baseline (I measured the same lag with Quake 3 and other native games): 5 frames or about ~83ms. This is pretty awful to begin with. I'm not really sure where all this lag comes from, but I blame the display. Since I measured all (Windows) browsers with the same setup, results are still comparable.

Firefox 14 had the fastest response time of only 5 frames, followed by IE9, Opera 12 and Safari 5.1.5 (Mac) with 6 frames. The real surprise here is Chrome's response time of 8 frames or 133ms – 50ms more than Firefox. This doesn't sound like much, but if you directly compare a real JavaScript game in Chrome and Firefox, you can definitely feel the difference.

The input lag for Mobile Safari on iOS6 is around the 5 frame, ~83ms mark as well. I also tried to measure the Android's "Browser" and the Chrome Beta on my Galaxy Nexus, but couldn't get accurate results.

Chrome on Android refused to render at more than 20 frames per second and the "Browser", while proclaiming to render at 60 frames per second, only really presented every fourth frame. This is clearly visible in the slow motion video – 4 boxes appear at the same time, instead of one after the other. This is also why HTML5 games in the "Browser" (damn, I hate that "name") still seem to stutter, even though they are "rendered" at 60 frames per second.

Android has a lot of catching up to do.

I build another simple website that behaves like Guitar Hero's lag calibration. As humans, we try to compensate for the lag ourselves by pressing a bit earlier, so the results from this aren't as accurate as measured with a camera, but you can clearly see and feel the difference between Chrome and about any other desktop browser.

From the video, it's quite obvious that the mouse lag in Chrome is much higher than in Firefox. However, the movement looks much smoother in Chrome. I guess you can't have everything - at least not yet.

FWIW, I did a little hack a couple years ago to get some similar measurements with Firefox -- see blog.mozilla.org/dolske/2010/05/26/a-little-mouse-hack/. I don't think it resulted in any direct fixes, but there's some data and video floating around somewhere from making latency measurements with it.

Have you tried testing the lag between mousemove events and the movement of the cursor? For example, if you draw a cursor on a canvas with the position from mousemove events, and compare it to the position of the normal mouse cursor.

There is a HUGE delay in chrome, but basically none in firefox and IE9. This is a problem for some types of games.

It feels like a significantly larger delay than for keyboard events, even though you are actually removing some of the delay by comparing two things on screen (removes usb and other i/o latency). I don't have any hard numbers though.

Could you try measuring this jsfiddle with your camera? I'm afraid that getting good numbers for something like this will be harder.

Nice post! I'm a little confused though, so maybe you can clarify. You say that you recorded 120fps video (8.3ms/frame) but the lag non-browser games is "5 frames or about ~83ms". 5*8.3=41.5ms. By "frames" do you mean monitor rather than camera frames, where your monitor's refresh rate is 60Hz (16.7ms refresh interval)? Thanks in advance!

I think I might have fixed this. What you need to do is hijack the game loop by turning the touch event into the driver for the game loop. Things like touchmove and mousemove are plenty fast, but they run out of sync with the game loop.

It works like this:

The game loop is set to an interval of 0 (so it's literally running as fast as it can).

Time is tracked between the last draw and the current draw. You use this to throttle the draw() call.

When you listen for mouse movement, you allow the mousemove listener to call draw() (instead of tick()).

When the input stops moving (not sure yet how to check for this... maybe check for two consecutive x,y that match?) you flip the loop back to the game.