IMPORTANT NOTE: I have updated this article and explained most of my knowledge about input lag on my website inputlag.science. Go there to an updated view and more measures.

As you may know, I’m a huge input lag nerd. I’ve spent a lot of time trying to figure out what can introduce latency in a video game setup. But lately as thought I would revisit how controller are tested.

Current methods

As far as I know there are two main ways to measure controller lag.

Teyah’s methodology

Controller Versus: plug two controllers in a system with a fighting game; bind the same button to both PCB; press it and count how many times the players have traded or not. The most notorious analysis is Teyah’s study (a lot of details there!).

Video interruption: use the video interruption input lag method on a very stable game (say BlazBlue CPE). By analysing the report card, you are able to estimate the lag distribution. Obviously, the one behind this idea is Noodalls who did a full report specifically on this topic. Having tested this method myself, it is pretty effective but requires some hardware.

Obviously, there is the LED / Camera standard input lag method which is not specific to controllers but you could still use this to get an approximation. As a matter of fact some people have done extensive studies about this. I’m also aware of this post where Jim Hejl shows their input lag system which does man-in-the-middle on usb on a wired PS4 but afaik there are no details.

The issue that I saw in those methods was twofold. Firstly, they are not really convenient and need a lot of data point to get the full details of the performance. Secondly, you always need a complete system (console or pc/game) which introduces a lot of unknown variables. Also, I just wanted to push the idea further.

That’s my mindset going in: I want direct test of the device, no extra system, and if possible easily reproducible.

Understanding USB for controllers

First, we need to understand how a system gets the state of a controller. I won’t go into great details here because USB can be hella complex and it’s not the purpose here to go too deep.

The general idea is the following:

When a device is plugged, the host (meaning the system which receives the controller) queries the device for it’s descriptor. This will describe what the device does and how to talk to the device.

For instance, it can say that it’s a controller and it will give the bus address to talk to and a polling rate.

(meaning the system which receives the controller) queries the device for it’s descriptor. This will describe the device does and to talk to the device. For instance, it can say that it’s a controller and it will give the bus address to talk to and a polling rate. Afterwards, if the host desires to get the status of the device, it can send a request on the desired address every few milliseconds according to the polling rate specifications.

The general polling protocol

This is a generic protocol, however it works only if the host knows what the device is talking about. Fortunately, there are two known protocols to get the state of controllers: HID (standard) and XInput (microsoft).

The main takeaway behind all this is: the device never sends its state by itself. The host asks the device, at his pace. And we will see that this has obviously significant impacts.

Hardware setup

Back to input lag. Knowing what we know, how could we measure input lag? The core idea is very raw: create a very small USB host, send a signal to press a button, measure the time when the device status will change. The remaining question is how to create a small USB host, and the device that changes everything is this thing: the USB Host Shield by Oleg Mazurov.

Arduino Uno + Usb Host Shield rev2 from Oleg Mazurov

I’m actually not using this exact configuration (I have a Arduino Mega and a clone of the USB Host Shield rev1) but it’s the same, just more ghetto. Retail price of this combo is around $50 but you easily find clones of those boards everywhere for way cheaper (even <10$ if you’re way cheap) and it will work the same.

This is able to talk to USB devices using a programmable device. The only thing we need now is to activate a button on the controller using a wire bound to one of the free pin. Assuming you have a common ground PCB, you can wire it like the following schematics. Note that you don’t need soldering just hold the wire it takes just a minute to run a benchmark.

Wire the button signal to pin 4. Diode is only here for (very) small protection.

If you don’t have a common ground controller (xbox 360 for instance) it will need a bit more wiring that I won’t detail here because it’s too specific and better electronic enthusiasts than me will be able to help. Check on the SRK forums if someone made a dualmod setup with your PCB and check what parts they used.

Now we just need to install the software I prepared (follow the install instructions there) and you’re good to go.

The experimentation protocol

Once everything is plugged correctly plugged, we can start our device and this is what it says in the Serial Monitor of the Arduino IDE:

The device is a Hori FC

It supports the HID protocol

Its polling rate is 5ms

Now if we send the command to launch the test it will change the state of the button 1000 times with random timings (to simulate random presses). The arduino program will time the duration between the change and when the state of the device changes.

Obviously, the polling rate will change a lot of things in the results. If your device is polled every 10ms, you won’t be able to have a 1ms latency all the time. You can tune that to three main modes.

Descriptor: use the value that was given by the device.

Usual: use the next power of 2 (1, 2, 4, 8, 16, 32ms). This is how usual systems like the PS4 or a PC will poll a device.

Overclock: just use 1ms. Some systems uses this overclocking like the undamned USB decoder (confirmed by undamned himself) to read the device as fast as possible.

Afterwards, we will have 1000 measures for each polling rate, for each device. That gives us plenty of data points. Now, we need to measure a bunch of devices and see what happens.

Results

For my first measure I’m going to focus on the Hori Fighting Commander 4, 1st Gen. This has a native 5ms polling interval.