Monday 22 January 2018

T440p, Haswell CPUs, bad battery life and CPU frequency-scaling

You have yourself a Haswell CPU (mine is a 4710MQ, but 4600, 4700, 4800 {MQ,HQ} et. al. will probably also apply), and you're running the latest LTS release (16.04) of Ubuntu (I'm actually running Xubuntu), and what you've found is that your batter life is terrible. I should be getting around 4h30m on this (6-cell) battery, but I get more like 1h50m. The reason? CPU frequency scaling.

The problem is that the kernel shipped with *some* 16.04 installations (depends on whether you've installed the refreshed 16.04.[123] LTS or not) have a bug in them that completely ruins the power saving of your laptop.

This is a plot of 70 seconds worth of data from scaling_cur_freq while my laptop is completely idle on the desktop (not a single core goes above 0.3% during this time):

X-axis: second, Y-axis: clock in khz

You can see all the makings of a screwy frequency-scaling algorithm. This is actually a well-known bug, but let's just cut to the chase. The problem is with the intel_pstate frequency-scaling driver. In some kernel versions that were shipped with 16.04 LTS, the intel_pstate actually pushes the CPU into turbo clocks from the most minor of activity.

The solution? Disable intel_pstate. Add intel_pstate=disable to /etc/default/grub.conf such that it looks something like this:

$ cat /etc/default/grub
# If you change this file, run 'update-grub' afterwards to update
# /boot/grub/grub.cfg.
# For full documentation of the options in this file, see:
#   info -f grub -n 'Simple configuration'

GRUB_DEFAULT=0
#GRUB_HIDDEN_TIMEOUT=0
GRUB_HIDDEN_TIMEOUT_QUIET=true
GRUB_TIMEOUT=10
GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
GRUB_CMDLINE_LINUX="intel_pstate=disable"

# Uncomment to enable BadRAM filtering, modify to suit your needs
# This works with Linux (no patch required) and with any kernel that obtains
# the memory map information from GRUB (GNU Mach, kernel of FreeBSD ...)
#GRUB_BADRAM="0x01234567,0xfefefefe,0x89abcdef,0xefefefef"

# Uncomment to disable graphical terminal (grub-pc only)
#GRUB_TERMINAL=console

# The resolution used on graphical terminal
# note that you can use only modes which your graphic card supports via VBE
# you can see them in real GRUB with the command `vbeinfo'
#GRUB_GFXMODE=640x480

# Uncomment if you don't want GRUB to pass "root=UUID=xxx" parameter to Linux
#GRUB_DISABLE_LINUX_UUID=true

# Uncomment to disable generation of recovery mode menu entries
#GRUB_DISABLE_RECOVERY="true"

# Uncomment to get a beep at grub start
#GRUB_INIT_TUNE="480 440 1"
$

Then update grub:

$ sudo update-grub
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-4.4.0-109-generic
Found initrd image: /boot/initrd.img-4.4.0-109-generic
Found linux image: /boot/vmlinuz-4.4.0-101-generic
Found initrd image: /boot/initrd.img-4.4.0-101-generic
Found linux image: /boot/vmlinuz-4.4.0-87-generic
Found initrd image: /boot/initrd.img-4.4.0-87-generic
Found linux image: /boot/vmlinuz-4.4.0-36-generic
Found initrd image: /boot/initrd.img-4.4.0-36-generic
Found memtest86+ image: /boot/memtest86+.elf
Found memtest86+ image: /boot/memtest86+.bin
done
$


Now reboot.


Your scaling driver will now be the acpi-cpufreq one. This one does a much better job of scaling the CPU frequencies than the buggy intel_pstate. You should get significant battery savings out of this change just by itself. If you're happy with what you have now, then feel free to quit reading now.

Who wants a slightly more tuned solution? Read on.

By default Ubuntu puts us into the ondemand governor:

$ cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
ondemand
ondemand
ondemand
ondemand
ondemand
ondemand
ondemand
ondemand
$

Disable it:

$ sudo systemctl disable ondemand
ondemand.service is not a native service, redirecting to systemd-sysv-install
Executing /lib/systemd/systemd-sysv-install disable ondemand
insserv: warning: current start runlevel(s) (empty) of script `ondemand' overrides LSB defaults (2 3 4 5).
insserv: warning: current stop runlevel(s) (2 3 4 5) of script `ondemand' overrides LSB defaults (empty).
$


Let's discover what ACPI events are generated when you unplug and re-plug your AC power supply:

$ acpi_listen
ac_adapter ACPI0003:00 00000080 00000000
ac_adapter ACPI0003:00 00000080 00000001
^C
$

So we see that we have the AC events. We're not actually going to use them for anything other than a trigger.

Create /etc/acpi/cpufreq-governor.sh and put this inside it:

/bin/sh
# Update cpufreq scaling-governor based on AC state.

( if [ $(cat /sys/class/power_supply/AC/online) -eq 1 ]; then
echo performance;
else
echo powersave;
fi ) | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor

Make sure to add execute permissions to it (chmod a+x).

Create an ACPI event /etc/acpi/events/ac-adapter and put this inside it:

# /etc/acpi/events/ac-adapter
#
# Switch CPU frequency-scaling governor depending on AC state.

event=ac_adapter ACPI0003:00 00000080 0000000[01]
action=/etc/acpi/cpufreq-governor.sh


This will run the scaling-governor-selection script any time there is a change in the state of the AC power supply. But what about boot? The AC state won't change at boot and we need to have the right governor selected then, too! So we'll create a service for that.

Create a SystemD service /etc/systemd/system/cpufreq-governor.service and put this inside it:

[Unit]
Description=Set the CPU Frequency Scaling governor to powersave/performance, depending on AC state.

[Service]
Type=oneshot
ExecStart=/etc/acpi/cpufreq-governor.sh

[Install]
WantedBy=multi-user.target

Enable it:

$ sudo systemctl daemon-reload
$ sudo systemctl enable cpufreq-governor
Created symlink from /etc/systemd/system/multi-user.target.wants/cpufreq-governor.service to /etc/systemd/system/cpufreq-governor.service.
$


Reboot.

Now your PC will use the right scaling governor when you boot and whenever the AC power supply state changes.

Thursday 18 January 2018

Nouveau and constant power-state cycling/loop in (X)Ubuntu 16.04/XFCE with Optimus

You've got yourself an Optimus machine, you've installed nouveau, and one thing that caught your eye is this:

entropy@symplex:~$ sudo cat /sys/kernel/debug/vgaswitcheroo/switch
0:DIS: :DynPwr:0000:02:00.0
1:IGD:+:Pwr:0000:00:02.0
entropy@symplex:~$ sudo cat /sys/kernel/debug/vgaswitcheroo/switch
0:DIS: :DynPwr:0000:02:00.0
1:IGD:+:Pwr:0000:00:02.0
entropy@symplex:~$ sudo cat /sys/kernel/debug/vgaswitcheroo/switch
0:DIS: :DynPwr:0000:02:00.0
1:IGD:+:Pwr:0000:00:02.0
entropy@symplex:~$ sudo cat /sys/kernel/debug/vgaswitcheroo/switch
0:DIS: :DynOff:0000:02:00.0
1:IGD:+:Pwr:0000:00:02.0
entropy@symplex:~$ sudo cat /sys/kernel/debug/vgaswitcheroo/switch
0:DIS: :DynOff:0000:02:00.0
1:IGD:+:Pwr:0000:00:02.0
entropy@symplex:~$ sudo cat /sys/kernel/debug/vgaswitcheroo/switch
0:DIS: :DynOff:0000:02:00.0
1:IGD:+:Pwr:0000:00:02.0
entropy@symplex:~$ sudo cat /sys/kernel/debug/vgaswitcheroo/switch
0:DIS: :DynPwr:0000:02:00.0
1:IGD:+:Pwr:0000:00:02.0
entropy@symplex:~$ sudo cat /sys/kernel/debug/vgaswitcheroo/switch
0:DIS: :DynPwr:0000:02:00.0
1:IGD:+:Pwr:0000:00:02.0
entropy@symplex:~$


Your card is cycling between the Dynamic power-on (DynPwr) and Dynamic power-off (DynOff) state. It's wasting your battery and you want it to stay off when it's not being used.

You'll also notice that dmesg shows you this:

[ 1096.319606] nouveau 0000:02:00.0: DRM: resuming kernel object tree...
[ 1096.362341] nouveau 0000:02:00.0: priv: HUB0: 10ecc0 ffffffff (1f70822c)
[ 1096.362355] nouveau 0000:02:00.0: priv: GPC0: 4188ac 00000001 (1a70822e)
[ 1096.434465] nouveau 0000:02:00.0: DRM: resuming client object trees...
[ 1101.536496] ACPI Warning: \_SB_.PCI0.PEG_.VID_._DSM: Argument #4 type mismatch - Found [Buffer], ACPI requires [Package] (20150930/nsarguments-95)
[ 1101.537262] ACPI Warning: \_SB_.PCI0.PEG_.VID_._DSM: Argument #4 type mismatch - Found [Buffer], ACPI requires [Package] (20150930/nsarguments-95)
[ 1101.537955] nouveau 0000:02:00.0: DRM: evicting buffers...
[ 1101.537962] nouveau 0000:02:00.0: DRM: waiting for kernel channels to go idle...
[ 1101.537988] nouveau 0000:02:00.0: DRM: suspending client object trees...
[ 1101.539366] nouveau 0000:02:00.0: DRM: suspending kernel object tree...
[ 1106.758460] nouveau 0000:02:00.0: DRM: resuming kernel object tree...
[ 1106.801176] nouveau 0000:02:00.0: priv: HUB0: 10ecc0 ffffffff (1b70822c)
[ 1106.801187] nouveau 0000:02:00.0: priv: GPC0: 4188ac 00000001 (1c70822e)
[ 1106.860253] nouveau 0000:02:00.0: DRM: resuming client object trees...
[ 1112.528066] ACPI Warning: \_SB_.PCI0.PEG_.VID_._DSM: Argument #4 type mismatch - Found [Buffer], ACPI requires [Package] (20150930/nsarguments-95)
[ 1112.528321] ACPI Warning: \_SB_.PCI0.PEG_.VID_._DSM: Argument #4 type mismatch - Found [Buffer], ACPI requires [Package] (20150930/nsarguments-95)
[ 1112.528545] nouveau 0000:02:00.0: DRM: evicting buffers...
[ 1112.528548] nouveau 0000:02:00.0: DRM: waiting for kernel channels to go idle...
[ 1112.528566] nouveau 0000:02:00.0: DRM: suspending client object trees...
[ 1112.529810] nouveau 0000:02:00.0: DRM: suspending kernel object tree...
[ 1117.593058] nouveau 0000:02:00.0: DRM: resuming kernel object tree...
[ 1117.635657] nouveau 0000:02:00.0: priv: HUB0: 10ecc0 ffffffff (1870822c)
[ 1117.635664] nouveau 0000:02:00.0: priv: GPC0: 4188ac 00000001 (1e70822e)
[ 1117.680262] nouveau 0000:02:00.0: DRM: resuming client object trees...

Over and over again. Suspending, resuming, suspending, resuming ...

Well, it turns out that it's a Window Manager tweak in XFCE(xfwm4) . This is what you're looking for:


Untick/unselect/disable the "Synchronise drawing to the vertical blank" and you will find that the problem disappears. The card will now stay in DynOff mode while it's not being used.

Tuesday 16 January 2018

No ALSA devices in Bitwig Studio 1.3.6 on Ubuntu

This is entirely the fault of the Bitwig developers, and after all of this time they have still not fixed the fault. I cannot take credit for this, please see the original thread where this was found.

Here is how the problem manifests itself: You'll go into Options > Preferences > Audio, select ALSA, and find that there are no compatible ALSA devices in the devices list.


The problem is that the Bitwig .deb package does not list libxcb-icccm4 as a dependency; presumably they assumed you'd have it installed. Simply install it:

$ sudo apt-get install libxcb-icccm4

ALSA devices should now be visible in the device selector. Now! If you get a message about the audio device being busy or that it could not be opened for some reason, remember that there is a high chance you're using a sound daemon of some sort. I'm going to assume you're using PulseAudio, because this is a post specific to Ubuntu, but if you're on some other distribution that uses a different sound daemon, then just look up what the equivalent for that daemon is.

To fix this, you need to run Bitwig studio like this:

$ pasuspender -- bitwig-studio

This suspends the PulseAudio sound daemon while Bitwig runs, so that Bitwig can have exclusive access to the underlying sound-card without going through PulseAudio, and then un-suspends it when you exit Bitwig.