Manage Wi-Fi latency and dynamic power-savings on Linux

Most of the time we want our battery-powered devices to consume as little power as possible. We all get more done when we don’t constantly have to chase down a charger. To that effect, the Linux kernel will try to power down the Wi-Fi module for short intervals when the Kernel doesn’t think it’s being used. This can lead to higher than desired network latency in some situations.

You may have noticed that network traffic to your laptop running Linux is sometimes delayed up to 300 milliseconds. Normally, you wouldn’t notice this. However, it can be detrimental to performance when you’re running any kind of server or task that relies on getting rapid responses to intermittent bursts of data over the Wi-Fi.

Some example tasks where network latency matters include online games, remote keyboard and mouse control (e.g. when using KDE Connect or Synergy), and distributed software compilation. (Your own use cases will probably be a bit more fun than these).

Dynamic power-saving and its effects on network latency

The Linux Kernel believes as most of us that good battery life is something to strive for. To achieve that goal, a myriad of different power-saving techniques is used by the Kernel. One of these techniques is the dynamic power-saving (DPS) feature found in recent Wi-Fi module models from Intel and Qualcomm Atheros.

When DPS is enabled, the Linux Kernel will put the Wi-Fi module to sleep to conserve energy when it hasn’t seen any network traffic over the last few milliseconds. The Kernel will dynamically adjust the duration of these naps based on access point (AP) capabilities and network usage. When there’s a constant flow of network traffic, your device will transmit and receive data at full speed without putting the Wi-Fi module to sleep. However, when there’s little or no network traffic (on a microsecond scale) and assuming your Wi-Fi AP supports this; your AP will buffer network traffic addressed to your device until a time in the future when your device and your AP agree to transmit the buffered data.

This introduces a delay in how responsive your device is to incoming connections. In return, your device’s network communication is made much more power-efficient.

If you use another device on your network that’s connected over Ethernet to ping your Wi-Fi-connected device, you can see a pong response in around 280 ms with DPS enabled and less than 1 ms with it disabled. With constant network traffic, the responses should come back much faster as the sleep intervals are tuned dynamically based on usage. DPS is usually an absolutely desired feature, and you shouldn’t turn it off!

What DPS can’t know anything about is whether a server or program on your computer is expecting intermittently incoming connections in the immediate future. When this is the case, it might be undesirable to conserve power at the cost of latency. Imagine that you open a program that requires lower network latency to function properly. You know this, the developer of the program knew this too, but the Linux Kernel doesn’t know anything about this expectation.

Signaling lower latency requirements to the Kernel

Users expect fast performance when running programs like Synergy or KDE Connect that work by sending keyboard and mouse inputs over the network. To avoid unwanted lag when moving the mouse cursor from one computer to another or before key-presses makes text appear on the screen, the program should make the Kernel aware of the lowered latency requirement so the latency introduced by DPS can be reduced.

Programs could previously communicate their need for reduced network latency directly to Kernel drivers over the pm-quos/network latency interface. When a program used this interface, the Kernel drivers could adjust how long network devices would enter sleep states and power down.

The pm-quos/network latency interface is still present in the Linux Kernel, but support was removed from all Wi-Fi drivers in because few programs had implemented it. I believe that it was a mistake to remove the interface implementations from the drivers, as I’ve recently run into quite a few different use cases where this kind of control would have been perfect.

E.g. Synergy and KDE Connect could have informed the Kernel to wait quite a bit longer before putting the Wi-Fi module to sleep. Humans could be given up to 5 seconds rather than a few microseconds before the Wi-Fi module is put to sleep for as long as these types of programs expect user activity.

Another example I ran into recently has to do with running a network distributed compilation. Often when compiling source code into built software, the compilation happens independently over many small files/jobs. With distributed compilation, all these small jobs are distributed among two or more computers in the network to speed up the build process. This assumes that I/O and network latency of transmitting these jobs back and forth over the network is smaller than the time it would take to compile it on the local system.

What I found was that the delay between receiving a set of jobs and sending back the result was just long enough for DPS to put the Wi-Fi module into a high power-saving mode. As the Wi-Fi connection consistently introduced lag before starting each job, the whole build process was slowed down significantly. This again resulted in the Wi-Fi-connected builders not being assigned more jobs as the job scheduler learned to not expect these build systems to quickly return any results.

This last scenario is a worst-case scenario. It’s akin to pinging a Wi-Fi-connected device every 6 seconds (ping -i6 wifi.example.com) when there’s no other network traffic. This would give the device plenty of time to enter a high power-savings mode and would lead to high latency.

As programs can’t ask the Kernel to tune down the power-savings anymore, users are only left turning DPS off completely. If you’re in need of reducing your Wi-Fi latency, you’ve these two options:

Temporarily disabling power-saving with llwr

I liked the idea of the pm-quos/network latency interface, so I made a small program called llwr (low-latency-Wi-Fi-required) that tries to replicate this interface as best it can. It’s a rather crude instrument that completely disables DPS, but only until the program you started exits. Think of it as the nice -16 command but for Wi-Fi network latency.

For example, to play the open-source fast-paced first-person shooter game Warsow with reduced network latency over Wi-Fi you’d start it the following command:

sudo llwr su $USERNAME -c warsow

This will disable DPS until you’re done with the game and exit it. At that time, DPS will be re-enabled and your laptop can start to conserve energy again.

You can get the latest release of llwr on GitHub where you’ll also find the sources and the issue tracker.

Permanently disable power-saving with NetworkManager

If you’ve decided that you prefer life without dynamic power-saving trying to save your laptop’s battery life, then you can disable the dynamic power-saving mod altogether. There are a lot of Kernel, Linux distribution, and software defaults that are involved in picking the default DPS policy for your device.

Networking on most user-friendly Linux distributions is managed by NetworkManager (sic.) If you don’t know whether your Linux system uses NetworkManager, then it probably is using NetworkManager. NetworkManager is usually at the top of the networking stack, so this is a good place to disable dynamic power-saving and ensure that it remains turned off.

  1. Create and open the file /etc/NetworkManager/conf.d/wifi-powersave.conf for editing.
  2. Put the following in the file and save:
    wifi.powersave = 2
  3. You’ll temporarily lose networking after this next step. Restart NetworkManager using the below command.
    service NetworkManager restart

You should now have disabled dynamic power-saving as long as NetworkManager remains in charge of your networking configuration. You can verify the change by running the command “iw dev YOUR-INTERFACE get power_save” now and again after a reboot.

This article only applies to drivers that support dynamic power-saving including recent Wi-Fi modules from Intel and Qualcomm Atheros. You can determine whether your module is supported by running the command “iw dev” to find your device’s interface name, followed by “iw dev YOUR-INTERFACE set power_save on” with root privileges. If you don’t get an error in return, then your device is supported. You can swap out “set” for “get” to get the current status, but this won’t tell you whether your Wi-Fi module supports dynamic power save or not.

Note that scripting “iw dev YOUR-INTERFACE set power_save off” on boot/resume isn’t enough as everything from the Kernel to NetworkManager will re-enable DPS when your network conditions and connection change, and after your device suspends and resumes, and at different stages in the system boot process.

In summary: Dynamic power-savings is generally a good thing, but occasionally you may want to turn it off when network latency is more important than battery life.