This is the motto of the FreeBSD operating system – The Power to Serve – which also greatly fits for the topic of this article. Decade ago (yes time flies) I even made a wallpaper with this motto – still available on the DeviatArt page.

Time for FreeBSD article covering its power management features. It also applies to FreeBSD Desktop series but its not limited to it. Popular opinion seems to be that FreeBSD is so server oriented that it lacks any power management mechanisms. Nothing more far from the truth. While less important on the desktop (but will still lower your electricity bill) or servers it is desirable to properly configure power management on laptops to so they will have longer battery life and will run more quiet.

I write this as the FreeBSD Handbook does not cover all that information in the 11.13. Power and Resource Management chapter. The FreeBSD on Laptops article part 4. Power Management is from the ancient times of FreeBSD 10.1-RELEASE. There is some information on the FreeBSD Wiki page but parts of it are outdated.

FreeBSD offers many mechanisms in the power management department:

power off devices without attached driver

scale CPU frequency and power

supports CPU sleep states (C1/C1E/C2/C3/…)

enabling/disabling Turbo Mode available in most CPUs

per USB device power management options

SATA/AHCI channels/controllers power management

suspend/resume support (along with using laptop lid for it)

support for vendor specific tools that help to measure power management

tools and ACPI support for fan speed control

tools and ACPI support for setting screen brightness

battery capacity status and running time estimation

network interfaces power saving options

One word about different files for the settings in the FreeBSD system:

/etc/rc.conf – does not require reboot just daemons reloading

– does not require reboot just daemons reloading /etc/sysctl.conf – does not require reboot – you can set them at runtime

– does not require reboot – you can set them at runtime /boot/loader.conf – these settings REQUIRE reboot

Here is the Table of Contents (non-clickable) for the article.

Information Battery Battery Wear CPU lscpu(1) dmesg(8)

CPU Frequency Scaling powerd(8) powerdxx(8) C-States CPU Turbo Mode

USB Devices

SATA/AHCI Power Management

Devices without Driver Nvidia Optimus

Suspend and Resume

Network Interfaces

Vendor Tools

DTrace

Other ZFS Applications

Hardware

UPDATE 1 – Graphics Card Power Saving

UPDATE 2 – AMD CPU Temperatures

UPDATE 3 – Suspend/Resume Tips

Information

Let’s start by describing where to get needed information about current CPU speed, used C-states, current power management modes for USB devices, battery capacity and remaining time, etc.

Battery

To get battery information you can use the acpiconf(8) tool. This is the acpiconf(8) output for my main battery (in the ThinkPad T420s laptop) with AC power attached.

% acpiconf -i 0 Design capacity: 44000 mWh Last full capacity: 37930 mWh Technology: secondary (rechargeable) Design voltage: 11100 mV Capacity (warn): 1896 mWh Capacity (low): 200 mWh Low/warn granularity: 1 mWh Warn/full granularity: 1 mWh Model number: 45N1037 Serial number: 28608 Type: LION OEM info: SANYO State: high Remaining capacity: 100% Remaining time: unknown Present rate: 0 mW Present voltage: 12495 mV

… and with AC power detached.

% acpiconf -i 0 Design capacity: 44000 mWh Last full capacity: 37930 mWh Technology: secondary (rechargeable) Design voltage: 11100 mV Capacity (warn): 1896 mWh Capacity (low): 200 mWh Low/warn granularity: 1 mWh Warn/full granularity: 1 mWh Model number: 45N1037 Serial number: 28608 Type: LION OEM info: SANYO State: high Remaining capacity: 100% Remaining time: 2:31 Present rate: 0 mW Present voltage: 12492 mV

Now as AC power is detached from the laptop the Remaining time: field will show you remaining time estimation for this single battery shows as 2:31 here (two hours and thirty one minutes).

Below is acpiconf(8) output for my secondary battery (in ThinkPad T420s ultrabay instead of DVD drive).

% acpiconf -i 1 Design capacity: 31320 mWh Last full capacity: 24510 mWh Technology: secondary (rechargeable) Design voltage: 10800 mV Capacity (warn): 1225 mWh Capacity (low): 200 mWh Low/warn granularity: 1 mWh Warn/full granularity: 1 mWh Model number: 45N1041 Serial number: 260 Type: LiP OEM info: SONY State: high Remaining capacity: 100% Remaining time: unknown Present rate: 0 mW Present voltage: 12082 mV

… and with AC power detached.

% acpiconf -i 1 Design capacity: 31320 mWh Last full capacity: 24510 mWh Technology: secondary (rechargeable) Design voltage: 10800 mV Capacity (warn): 1225 mWh Capacity (low): 200 mWh Low/warn granularity: 1 mWh Warn/full granularity: 1 mWh Model number: 45N1041 Serial number: 260 Type: LiP OEM info: SONY State: discharging Remaining capacity: 98% Remaining time: 1:36 Present rate: 14986 mW Present voltage: 11810 mV

With AC power detached it shows the Remaining time: as 1:36 for the secondary battery.

So its total 4:07 time on battery estimated. The same time in minutes ( 247 ) will be shown in the sysctl(8) value named hw.acpi.battery.time as shown below.

% sysctl hw.acpi.battery.time hw.acpi.battery.time: 247

You can also get more ‘complete’ battery information with below sysctl(8) values under hw.acpi.battery MIB.

% sysctl hw.acpi.battery hw.acpi.battery.info_expire: 5 hw.acpi.battery.units: 2 hw.acpi.battery.state: 1 hw.acpi.battery.time: 247 hw.acpi.battery.life: 99

The hw.acpi.battery.time will show you ‘ -1 ‘ value if you have AC power attached.

% sysctl hw.acpi.battery hw.acpi.battery.info_expire: 5 hw.acpi.battery.units: 2 hw.acpi.battery.state: 0 hw.acpi.battery.time: -1 hw.acpi.battery.life: 100

Battery Wear

As time passes by batteries lose their ‘design’ capacity. After 1-2 years such battery can have only 70% or less of its original efficiency.

All the information needed to check that is provided by the acpiconf(8) command with Design capacity: and Last full capacity: values. I have made a battery-capacity.sh script that will tell you what the current battery efficiency is. Here is how it looks in action.

% battery-capacity.sh 0 Battery '0' model '45N1037' has efficiency: 86% % battery-capacity.sh 1 Battery '1' model '45N1041' has efficiency: 78%

Here is the battery-capacity.sh script itself.

#! /bin/sh if [ ${#} -ne 1 ] then echo "usage: ${0##*/} BATTERY" exit fi if acpiconf -i ${1} 1> /dev/null 2> /dev/null then DATA=$( acpiconf -i ${1} ) MAX=$( echo "${DATA}" | grep '^Design\ capacity:' | awk -F ':' '{print $2}' | tr -c -d '0-9' ) NOW=$( echo "${DATA}" | grep '^Last\ full\ capacity:' | awk -F ':' '{print $2}' | tr -c -d '0-9' ) MOD=$( echo "${DATA}" | grep '^Model\ number:' | awk -F ':' '{print $2}' | awk '{print $1}' ) echo -n "Battery '${1}' model '${MOD}' has efficiency: " printf '%1.0f%%

' $( bc -l -e "scale = 2; ${NOW} / ${MAX} * 100" -e quit ) else echo "NOPE: Battery '${1}' does not exists on this system." echo "INFO: Most systems has only '0' or '1' batteries." exit 1 fi

CPU

To get information about current CPU’s you will have to use dev.cpu MIB or dev.cpu.0 for the first physical CPU core.

% sysctl dev.cpu.0 dev.cpu.0.cx_method: C1/hlt C2/io dev.cpu.0.cx_usage_counters: 412905 0 dev.cpu.0.cx_usage: 100.00% 0.00% last 290us dev.cpu.0.cx_lowest: C1 dev.cpu.0.cx_supported: C1/1/1 C2/3/104 dev.cpu.0.freq_levels: 2501/35000 2500/35000 2200/29755 2000/26426 1800/23233 1600/20164 1400/17226 1200/14408 1000/11713 800/9140 dev.cpu.0.freq: 800 dev.cpu.0.%parent: acpi0 dev.cpu.0.%pnpinfo: _HID=none _UID=0 dev.cpu.0.%location: handle=\_PR_.CPU0 dev.cpu.0.%driver: cpu dev.cpu.0.%desc: ACPI CPU

If you load the coretemp(4) kernel module with kldload(8) command you will get additional temperature information.

Below is same sysctl(8) dev.cpu.0 MIB with coretemp(4) kernel module loaded.

% sysctl dev.cpu.0 dev.cpu.0.temperature: 49.0C dev.cpu.0.coretemp.throttle_log: 0 dev.cpu.0.coretemp.tjmax: 100.0C dev.cpu.0.coretemp.resolution: 1 dev.cpu.0.coretemp.delta: 51 dev.cpu.0.cx_method: C1/hlt C2/io dev.cpu.0.cx_usage_counters: 16549 0 dev.cpu.0.cx_usage: 100.00% 0.00% last 1489us dev.cpu.0.cx_lowest: C1 dev.cpu.0.cx_supported: C1/1/1 C2/3/104 dev.cpu.0.freq_levels: 2501/35000 2500/35000 2200/29755 2000/26426 1800/23233 1600/20164 1400/17226 1200/14408 1000/11713 800/9140 dev.cpu.0.freq: 800 dev.cpu.0.%parent: acpi0 dev.cpu.0.%pnpinfo: _HID=none _UID=0 dev.cpu.0.%location: handle=\_PR_.CPU0 dev.cpu.0.%driver: cpu dev.cpu.0.%desc: ACPI CPU

Let me describe some most useful ones.

CPU core temperature.

dev.cpu.0.temperature: 49.0C

CPU supported C-states (C1 and C2 for this CPU).

dev.cpu.0.cx_supported: C1/1/1 C2/3/104

CPU statistics for C-states usage (only C1 state been used).

dev.cpu.0.cx_usage_counters: 16549 0

dev.cpu.0.cx_usage: 100.00% 0.00% last 1489us

CPU maximum (most deep) C state enabled.

dev.cpu.0.cx_lowest: C1

CPU supported frequency levels with power usage after the ‘ / ‘ character. The 2500/35000 can be read as 2.5 GHz frequency with 35 W power usage and 2501 is the Turbo Mode. The lowest is 800 MHz with about 9 W usage.

dev.cpu.0.freq_levels: 2501/35000 2500/35000 2200/29755 2000/26426 1800/23233 1600/20164 1400/17226 1200/14408 1000/11713 800/9140

CPU current frequency (will vary when You use powerd(8) or powerdxx(8) daemon).

dev.cpu.0.freq: 800

The hw.acpi.thermal.tz0.temperature MIB will also show you current thermal zone temperature.

% sysctl hw.acpi.thermal.tz0.temperature hw.acpi.thermal.tz0.temperature: 49.1C

To check how many cores you have use these commands.

% grep FreeBSD/SMP /var/run/dmesg.boot FreeBSD/SMP: Multiprocessor System Detected: 2 CPUs FreeBSD/SMP: 1 package(s) x 2 core(s) % sysctl kern.smp.cpus kern.smp.cpus: 2

If my description does not feel useful then you should also check the -d flag for sysctl(8) command as shown below.

% sysctl -d dev.cpu.0.freq dev.cpu.0.freq: Current CPU frequency

lscpu(1)

There is also third party tool called lscpu(8) that will describe your CPU features and model. You will have to add it from packages.

# pkg install lscpu

To make lscpu(8) work the cpuctl(4) kernel module is needed.

Here is how it looks for my dual core CPU.

# kldload cpuctl # lscpu Architecture: amd64 Byte Order: Little Endian Total CPU(s): 2 Thread(s) per core: 2 Core(s) per socket: 2 Socket(s): 0 Vendor: GenuineIntel CPU family: 6 Model: 42 Model name: Intel(R) Core(TM) i5-2520M CPU @ 2.50GHz Stepping: 7 L1d cache: 32K L1i cache: 32K L2 cache: 256K L3 cache: 3M Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 cflsh ds acpi mmx fxsr sse sse2 ss htt tm pbe sse3 pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic popcnt tsc_deadline aes xsave osxsave avx syscall nx rdtscp lm lahf_lm

dmesg(8)

Also dmesg(8) command (or /var/run/dmesg.boot file after longer uptime) covers your CPU model and features information.

% grep CPU /var/run/dmesg.boot CPU: Intel(R) Core(TM) i5-2520M CPU @ 2.50GHz (2491.97-MHz K8-class CPU) FreeBSD/SMP: Multiprocessor System Detected: 2 CPUs cpu0: on acpi0 coretemp0: on cpu0

CPU Frequency Scaling

For CPU scaling feature you may use the powerd(8) daemon available in the FreeBSD base system or powerdxx(8) from the FreeBSD Ports or packages. The powerdxx(8) daemon aims to better scale multicore systems and not turning all cores to high state when there is moderate load on the system but some people may prefer that approach to have full power available when they do anything and to save power when they do nothing. Thus powerd(8) is not better then powerdxx(8) or vice versa. They are just different so that gives you more options for your needs.

No matter which one you will choose it has to be configured in the /etc/rc.conf file.

powerd(8)

Here are the options for powerd(8) daemon.

powerd_enable=YES powerd_flags="-n adaptive -a hiadaptive -b adaptive -m 800 -M 1600"

The -n option of for the unknown state – if for some reason the powerd(8) will not be able to determine if you are running on the AC power or battery. The -a is for AC power and -b for running on the battery. The adaptive setting is less ‘aggressive’ so its more battery time friendly. The hiadaptive is more aggressive this its preferred when you are running on AC power. The -m option sets minimum CPU frequency to be used and -M the maximum. Both in MHz units. Check powerd(8) man page for more details.

powerdxx(8)

First you will need to install it.

# pkg install powerdxx

Then its options are identical as those of powerd(8) daemon.

powerdxx_enable=YES powerdxx_flags="-n adaptive -a hiadaptive -b adaptive -m 800 -M 1600"

Check the powerdxx(8) section above for the flags/parameters description.

Decade ago CPU frequency scaling on FreeBSD was not that ‘easy’ as it is now, you may check my old HOWTO: FreeBSD CPU Scaling and Power Saving in that topic from 2008.

C-States

The C-states can be configured in the /etc/rc.conf file with these options.

performance_cx_lowest

economy_cx_lowest

The economy_cx_lowest parameter is for running on battery and performance_cx_lowest parameter is for running on AC power. Both are set using the /etc/rc.d/power_profile script used by rc(8) subsystem. It sets the hw.acpi.cpu.cx_lowest parameter which sets/controls all dev.cpu.*.cx_lowest values. You can also track the changes in the /var/log/messages file when you attach/detach the AC power.

% tail -f /var/log/messages Nov 28 13:14:42 t420s power_profile[48231]: changed to 'economy' Nov 28 13:14:46 t420s power_profile[56835]: changed to 'performance'

Usually I jest use these values.

performance_cx_lowest=C1 economy_cx_lowest=Cmax

These settings above are generally sufficient for most systems. To check which C-states your CPU supports get the value of dev.cpu.0.cx_supported MIB.

% sysctl dev.cpu.0.cx_supported dev.cpu.0.cx_supported: C1/1/1 C2/3/104

My CPU supports only C1 and C2 but yours may support more. I remember once when using some old Core 2 Duo laptop that the C2 state had quite ‘noticeable’ delay when getting back from C1 (running) state to C2 (sleep) state so following setting is needed. You do not use the performance_cx_lowest and economy_cx_lowest parameters. You set the first core to C1 and all other cores to C2. This way even on battery you have fully responsive system and all other cores may sleep and save energy.

For example if You would have 4 cores and your maximum (deepest) supported C-state would be C3, then you would put these into the /etc/sysctl.conf file.

% grep cx_lowest /etc/sysctl.conf dev.cpu.0.cx_lowest=C1 dev.cpu.1.cx_lowest=C3 dev.cpu.2.cx_lowest=C3 dev.cpu.3.cx_lowest=C3

CPU Turbo Mode

There are two ways to enable Turbo mode. One way is to set powerd(8) or powerdxx(8) daemon with maximum frequency set above nominal CPU speed. For example if you have CPU described as dual-core 2.3 GHz then set the maximum speed with -M flag to 4000 for example (which would mean 4GHz). If you do not use CPU frequency scaling daemon then you will use dev.cpu.0.freq parameter with highest (first) value from the dev.cpu.0.freq_levels MIB.

Supported CPU frequency levels on my system.

% sysctl dev.cpu.0.freq_levels dev.cpu.0.freq_levels: 2501/35000 2500/35000 2200/29755 2000/26426 1800/23233 1600/20164 1400/17226 1200/14408 1000/11713 800/9140

The highest value (left) is 2501/35000 so I need to set dev.cpu.0.freq parameter with this value to use Turbo Mode. You need to only use the ‘frequency’ value part because if you paste it with power requirements description it will fail.

# sysctl dev.cpu.0.freq=2501/35000 sysctl: invalid integer '2501/35000'

This is how it should be used.

# sysctl dev.cpu.0.freq=2501 dev.cpu.0.freq: 800 -> 2501

USB Devices

To list attached USB devices use the usbconfig(8) tool.

% usbconfig ugen1.1: at usbus1, cfg=0 md=HOST spd=SUPER (5.0Gbps) pwr=SAVE (0mA) ugen2.1: at usbus2, cfg=0 md=HOST spd=HIGH (480Mbps) pwr=SAVE (0mA) ugen0.1: at usbus0, cfg=0 md=HOST spd=HIGH (480Mbps) pwr=SAVE (0mA) ugen2.2: at usbus2, cfg=0 md=HOST spd=HIGH (480Mbps) pwr=SAVE (0mA) ugen0.2: at usbus0, cfg=0 md=HOST spd=HIGH (480Mbps) pwr=SAVE (0mA) ugen0.3: at usbus0, cfg=0 md=HOST spd=FULL (12Mbps) pwr=ON (100mA) ugen2.3: at usbus2, cfg=0 md=HOST spd=HIGH (480Mbps) pwr=SAVE (0mA)

You will see that pwr parameter (short for power) will show you current power setting which can be:

ON

OFF

SAVE

To set new USB power option for the ugen1.1 device also use the usbconfig(8) tool with the power_save parameter in the following way.

# usbconfig -u 1 -a 1 power_save

The USB power management does not have dedicated config file on FreeBSD so we will put them into universal /etc/rc.local file which is being run at the end of the start-up process managed by the rc(8) subsystem. Here is the added content with exception for the ‘ Lenovo USB Receiver ‘ which is my wireless mouse.

% grep -A 10 POWER /etc/rc.local # POWER SAVE USB DEVICES usbconfig \ | grep -v 'Lenovo USB Receiver' \ | awk '{print $1}' \ | sed 's|ugen||'g \ | tr -d : \ | awk -F '.' '{print $1 " " $2 }' \ | while read U A do usbconfig -u ${U} -a ${A} power_save 2> /dev/null done

It’s good idea to NOT save power for mouse or tracked devices because you will probably find it annoying to have to wait about a second each time you would like to use it. I use a for loop to set power saving for all USB devices except wireless USB mouse (identified as ‘ Lenovo USB Receiver ‘ device).

SATA/AHCI Power Management

FreeBSD offers AHCI channels power management via acpich(4) driver. These power management settings cen be set at boot using the hint.ahcich.*.pm_level parameter in the /boot/loader.conf file. I use configuration up to 8 channels while I only have three.

% grep ahcich /var/run/dmesg.boot ahcich0: at channel 0 on ahci0 ahcich1: at channel 1 on ahci0 ahcich4: at channel 4 on ahci0 ada0 at ahcich0 bus 0 scbus0 target 0 lun 0

That is because settings for non-existent devices are harmless and will not display any error messages but you will not have to use different settings for various systems which saves time. This is the hint.ahcich.*.pm_level description from the ahci(4) man page.

hint.ahcich.X.pm_level controls SATA interface Power Management for the specified channel, allowing some power to be saved at the cost of additional command latency. Some controllers, such as ICH8, do not implement modes 2 and 3 with NCQ used. Because of artificial entering latency, performance degradation in modes 4 and 5 is much smaller then in modes 2 and 3.

Possible power management options are:

0 – interface Power Management is disabled (default)

– interface Power Management is disabled (default) 1 – device is allowed to initiate PM state change, host is passive

– device is allowed to initiate PM state change, host is passive 2 – host initiates PARTIAL PM state transition every time port becomes idle

– host initiates PARTIAL PM state transition every time port becomes idle 3 – host initiates SLUMBER PM state transition every time port becomes idle

– host initiates SLUMBER PM state transition every time port becomes idle 4 – driver initiates PARTIAL PM state transition 1ms after port becomes idle

– driver initiates PARTIAL PM state transition 1ms after port becomes idle 5 – driver initiates SLUMBER PM state transition 125ms after port becomes idle

Here are my setting from the /boot/loader.conf file.

# AHCI POWER MANAGEMENT FOR EVERY USED CHANNEL (ahcich 0-7) hint.ahcich.0.pm_level=5 hint.ahcich.1.pm_level=5 hint.ahcich.2.pm_level=5 hint.ahcich.3.pm_level=5 hint.ahcich.4.pm_level=5 hint.ahcich.5.pm_level=5 hint.ahcich.6.pm_level=5 hint.ahcich.7.pm_level=5

Devices without Driver

FreeBSD has power saving option to not power devices that does not have attached driver. Its called hw.pci.do_power_nodriver and you can set it in the /boot/loader.conf file. Here is its description from then pci(4) man page.

hw.pci.do_power_nodriver (Defaults to 0) Place devices into a low power state (D3) when a suitable device driver is not found.

It can be set to one of the following values:

0 – All devices are left fully powered (defaults).

– All devices are left fully powered (defaults). 1 – Like ‘ 2 ‘ except that storage controllers are also not powered down.

– Like ‘ ‘ except that storage controllers are also not powered down. 2 – Powers down most devices (display/memory/peripherals not powered down).

– Powers down most devices (display/memory/peripherals not powered down). 3 – Powers down all PCI devices without a device driver.

Here is my setting from the /boot/loader.conf file.

# POWER OFF DEVICES WITHOUT ATTACHED DRIVER hw.pci.do_power_nodriver=3

The pciconf(8) utility will show you what devices are in your system and which driver is attached to it. If no driver is attached you will see none*@ for such devices, as none0@ below. You can also check man page for most drivers like em(4) man page for em0 device or xhci(4) page for xhci0 device.

% pciconf -l hostb0@pci0:0:0:0: class=0x060000 card=0x21d217aa chip=0x01048086 rev=0x09 hdr=0x00 vgapci0@pci0:0:2:0: class=0x030000 card=0x21d217aa chip=0x01268086 rev=0x09 hdr=0x00 none0@pci0:0:22:0: class=0x078000 card=0x21d217aa chip=0x1c3a8086 rev=0x04 hdr=0x00 em0@pci0:0:25:0: class=0x020000 card=0x21ce17aa chip=0x15028086 rev=0x04 hdr=0x00 ehci0@pci0:0:26:0: class=0x0c0320 card=0x21d217aa chip=0x1c2d8086 rev=0x04 hdr=0x00 hdac0@pci0:0:27:0: class=0x040300 card=0x21d217aa chip=0x1c208086 rev=0x04 hdr=0x00 pcib1@pci0:0:28:0: class=0x060400 card=0x21d217aa chip=0x1c108086 rev=0xb4 hdr=0x01 pcib2@pci0:0:28:1: class=0x060400 card=0x21d217aa chip=0x1c128086 rev=0xb4 hdr=0x01 pcib3@pci0:0:28:3: class=0x060400 card=0x21d217aa chip=0x1c168086 rev=0xb4 hdr=0x01 pcib4@pci0:0:28:4: class=0x060400 card=0x21d217aa chip=0x1c188086 rev=0xb4 hdr=0x01 ehci1@pci0:0:29:0: class=0x0c0320 card=0x21d217aa chip=0x1c268086 rev=0x04 hdr=0x00 isab0@pci0:0:31:0: class=0x060100 card=0x21d217aa chip=0x1c4f8086 rev=0x04 hdr=0x00 ahci0@pci0:0:31:2: class=0x010601 card=0x21d217aa chip=0x1c038086 rev=0x04 hdr=0x00 ichsmb0@pci0:0:31:3: class=0x0c0500 card=0x21d217aa chip=0x1c228086 rev=0x04 hdr=0x00 iwn0@pci0:3:0:0: class=0x028000 card=0x11118086 chip=0x42388086 rev=0x3e hdr=0x00 sdhci_pci0@pci0:5:0:0: class=0x088000 card=0x21d217aa chip=0xe8221180 rev=0x07 hdr=0x00 xhci0@pci0:13:0:0: class=0x0c0330 card=0x01941033 chip=0x01941033 rev=0x04 hdr=0x00

You can also use -v flag to get more detailed information.

% pciconf -l -v (...) xhci0@pci0:13:0:0: class=0x0c0330 card=0x01941033 chip=0x01941033 rev=0x04 hdr=0x00 vendor = 'NEC Corporation' device = 'uPD720200 USB 3.0 Host Controller' class = serial bus subclass = USB

Nvidia Optimus

If for some reason your BIOS/UEFI firmware does not allow you to disable Nvidia discrete graphics card you may use this script to disable it so it will not drain power from your system. It requires the acpi_call(4) kernel module which is provided by the acpi_call package.

# mkdir /root/bin # cd /root/bin # fetch https://people.freebsd.org/~xmj/turn_off_gpu.sh # pkg install acpi_call # kldload acpi_call # chmod +x /root/bin/turn_off_gpu.sh # /root/bin/turn_off_gpu.sh

You may add it to the /etc/rc.local file after the USB power saving options with this entry.

# DISABLE NVIDIA CARD /root/bin/turn_off_gpu.sh

It successd it will store the working ACPI call in the /root/.gpu_method file and execute it each next time.

Suspend and Resume

The biggest enemies of supend/resume mechanism are bugs in your BIOS/UEFI firmware for your hardware. Sometimes disabling Bluetooth helps – that is the option for ThinkPad T420s for example. To check which suspend modes are supported on your system check the hw.acpi.supported_sleep_state MIB from sysctl(8) subsystem.

% sysctl hw.acpi.supported_sleep_state hw.acpi.supported_sleep_state: S3 S4 S5

To enter ACPI S3 sleep state (suspend) you can use acpiconf(8) tool or zzz(8) tool.

# zzz

… or with acpiconf(8) tool.

# acpiconf -s 3

Its exactly the same as stated in the zzz(8) man page.

You can also set sysctl(8) value that everytime you close your laptop lid your system will go to sleep. To achieve that put hw.acpi.lid_switch_state=S3 into the /etc/sysctl.conf file. No matter if you put you hardware to sleep by command or by closing the lid your laptop will resume after opening the lid. Of course if you haven’t closed the lid after the zzz(8) command you will either have to close and open the lid or push the power button to resume. Of course you may also suspend/resume desktops or even your backup server if it has its purpose. It’s not limited to laptops only.

There are also dedicated kernel modules for various vendor ACPI subsystems. Here they are:

/boot/kernel/acpi_asus_wmi.ko

/boot/kernel/acpi_asus.ko

/boot/kernel/acpi_dock.ko

/boot/kernel/acpi_fujitsu.ko

/boot/kernel/acpi_hp.ko

/boot/kernel/acpi_ibm.ko

/boot/kernel/acpi_panasonic.ko

/boot/kernel/acpi_sony.ko

/boot/kernel/acpi_toshiba.ko

/boot/kernel/acpi_video.ko

/boot/kernel/acpi_wmi.ko

For example if you have IBM/Lenovo ThinkPad the you will use the acpi_ibm.ko kernel module.

# kldload acpi_ibm

After loading each module you will get new sysctl(8) values for your use. For example related to fan speed, keyboard backlit or screen brightness. Below is new dev.acpi_ibm section in sysctl(8) after loading the acpi_ibm(4) kernel module.

% sysctl dev.acpi_ibm dev.acpi_ibm.0.handlerevents: NONE dev.acpi_ibm.0.mic_led: 0 dev.acpi_ibm.0.fan: 0 dev.acpi_ibm.0.fan_level: 0 dev.acpi_ibm.0.fan_speed: 0 dev.acpi_ibm.0.wlan: 1 dev.acpi_ibm.0.bluetooth: 0 dev.acpi_ibm.0.thinklight: 0 dev.acpi_ibm.0.mute: 0 dev.acpi_ibm.0.volume: 0 dev.acpi_ibm.0.lcd_brightness: 0 dev.acpi_ibm.0.hotkey: 1425 dev.acpi_ibm.0.eventmask: 134217727 dev.acpi_ibm.0.events: 1 dev.acpi_ibm.0.availmask: 134217727 dev.acpi_ibm.0.initialmask: 2060 dev.acpi_ibm.0.%parent: acpi0 dev.acpi_ibm.0.%pnpinfo: _HID=LEN0068 _UID=0 dev.acpi_ibm.0.%location: handle=\_SB_.PCI0.LPC_.EC__.HKEY dev.acpi_ibm.0.%driver: acpi_ibm dev.acpi_ibm.0.%desc: IBM ThinkPad ACPI Extras dev.acpi_ibm.%parent:

Here are descriptions of more interesting ones.

This one will turn the LED light on the Microphone mute button.

dev.acpi_ibm.0.mic_led

Select if you want to manage CPU fan ( 0 ) or leave it to the manufacturer defaults ( 1 ).

dev.acpi_ibm.0.fan

If CPU fan is enabled, set its speed.

dev.acpi_ibm.0.fan_level

This one will tell you how fast the CPU fan is spinning (in RPMs).

dev.acpi_ibm.0.fan_speed

Enable/disable WiFi (if its enabled in BIOS).

dev.acpi_ibm.0.wlan

Enable/disable Bluetooth (if its enabled in BIOS).

dev.acpi_ibm.0.bluetooth

Enable/disable ThinkLight.

dev.acpi_ibm.0.thinklight

Mute/unmute speakers.

dev.acpi_ibm.0.mute

Speakers volume.

dev.acpi_ibm.0.volume

Screen brightness.

dev.acpi_ibm.0.lcd_brightness

For most of the cases its not needed to use them as you will probably just use the vendor defined keyboard shortcuts (probably with Fn key) or vendor specific dedicated buttons. Sometimes you want to create/use your own setup or need custom keyboard shortcuts, or you want to control the fan speed depending on the CPU temperature other way then your vendor predefined it. This is when these dedicated ACPI kernel modules are most useful.

For example I recently thought that my CPU fan seems to be little louder then it should be so I created custom cron(8) based acpi-thinkpad-fan.sh script to use lower fan speeds or even lower quieter speeds when CPU temperature is low enough.

I will post it here. Maybe you will find it useful for your purposes. To describe it shortly it disables the fan when CPU temperature is below 50 (C) degrees, it sets it to level ‘1’ if its between 50 (C) and 60 (C) degrees and sets it to level ‘3’ when temperature reaches more then 60 (C) degrees.

#! /bin/sh if ! kldstat | grep -q acpi_ibm.ko then doas kldload acpi_ibm fi doas sysctl dev.acpi_ibm.0.fan=0 1> /dev/null TEMP=$( sysctl -n hw.acpi.thermal.tz0.temperature | awk -F'.' '{print $1}' ) if [ ${TEMP} -lt 50 ] then doas sysctl dev.acpi_ibm.0.fan_level=0 1> /dev/null exit 0 fi if [ ${TEMP} -lt 60 ] then doas sysctl dev.acpi_ibm.0.fan_level=1 1> /dev/null exit 0 fi if [ ${TEMP} -ge 60 ] then doas sysctl dev.acpi_ibm.0.fan_level=3 1> /dev/null exit 0 fi

… and here is its crontab(5) entry:

% crontab -l # ACPI/IBM/FAN * * * * * ~/scripts/acpi-thinkpad-fan.sh

Network Interfaces

There is also ifconfig(8) option to save power if a driver supports such feature, its called powersave and its used like that.

# ifconfig wlan0 powersave

I use it in my network.sh network management script described broadly in the FreeBSD Network Management with network.sh article.

Vendor Tools

There are also vendor tools available on FreeBSD like powermon(8) for example. Remember that it requires cpuctl(4) kernel module to work.

# pkg install powermon # kldload cpuctl # powermon Intel(R) Core(TM) i5-2520M CPU @ 2.50GHz (Arch: Sandy Bridge, Limit: 44W) 5.11W [=======> ] Package: Uncore: x86 Cores: GPU: Current: 5.11W Current: 3.17W Current: 1.73W Current: 0.21W Total: 98.33J Total: 60.86J Total: 33.49J Total: 3.98J

DTrace

The dynamic tracing framework that like ZFS found its way from Solaris/Illumos to FreeBSD may be also useful weapon in the battle for more time on your battery.

First add the dtrace-toolkit package.

# pkg install dtrace-toolkit

Your system stops saving energy or wakes CPU up because something needs to be run/done. To check what is run on your system you mostly run ps(1) or top(1) utilities but that will not show you what exactly is being started or how often something is being run. This is where DTrace comes with help.

We will use the /usr/share/dtrace/toolkit/execsnoop script from the dtrace-toolkit package. It will print EVERY COMMAND that is being run with all its arguments.It will remain silent when no commands are run, be advised.

Here is example output for my dzen2 toolbar update.

# /usr/local/share/dtrace-toolkit/execsnoop UID PID PPID ARGS 1000 97748 97509 /usr/local/bin/zsh -c ~/scripts/dzen2-update.sh > ~/.dzen2-fifo 1000 97748 1 /bin/sh /home/vermaden/scripts/dzen2-update.sh 1000 99157 97748 sysctl -n kern.smp.cpus 1000 311 97748 ps ax -o %cpu,rss,command -c 1000 3118 1521 awk -v SMP=200 /\ idle$/ {printf("%.1f%%",SMP-$1)} 1000 4462 97748 date +%Y/%m/%d/%a/%H:%M 1000 4801 97748 sysctl -n dev.cpu.0.freq 1000 6009 97748 sysctl -n hw.acpi.thermal.tz0.temperature 1000 6728 97748 sysctl -n vm.stats.vm.v_inactive_count 1000 7043 97748 sysctl -n vm.stats.vm.v_free_count 1000 7482 97748 sysctl -n vm.stats.vm.v_cache_count 1000 10363 8568 bc -l 1000 10863 10363 dc -x 1000 13143 7773 grep --color -q ^\. 1000 13798 97748 /bin/sh /home/vermaden/scripts/__conky_if_ip.sh 1000 15089 14235 ifconfig -u 1000 16439 14235 grep -v 127.0.0.1 1000 17738 14235 grep -c inet 1000 19069 18612 ifconfig -l -u 1000 19927 18612 sed s/lo0//g 1000 20772 13798 ifconfig wlan0 1000 23388 21410 grep ssid 1000 24588 13798 grep -q " 1000 25965 25282 awk /ssid/ {print $2} 1000 27917 27217 awk /inet / {print $2} 1000 29941 97748 /bin/sh /home/vermaden/scripts/__conky_if_gw.sh 1000 32808 31412 route -n -4 -v get default 1000 34012 31412 awk END{print $2} 1000 34895 97748 /bin/sh /home/vermaden/scripts/__conky_if_dns.sh 1000 36118 34895 awk /^nameserver/ {print $2; exit} /etc/resolv.conf 1000 37628 97748 /bin/sh /home/vermaden/scripts/__conky_if_ping.sh dzen2 1000 38829 37628 ping -c 1 -s 0 -t 1 -q 9.9.9.9 1000 42079 41566 mixer -s vol 1000 42177 41566 awk -F : {printf("%s",$2)} 1000 44434 43254 zfs list -H -d 0 -o name,avail 1000 45866 43254 awk {printf("%s/%s ",$1,$2)} 1000 47004 97748 /bin/sh /home/vermaden/scripts/__conky_battery_separate.sh dzen2 1000 48282 47004 sysctl -n hw.acpi.battery.units 1000 49494 47004 sysctl -n hw.acpi.battery.life 1000 49948 47004 sysctl -n hw.acpi.acline 1000 52073 51441 acpiconf -i 0 1000 53055 51441 awk /^State:/ {print $2} 1000 53981 53186 acpiconf -i 0 1000 55354 53186 awk /^Remaining capacity:/ {print $3} 1000 55968 55631 acpiconf -i 1 1000 57187 55631 awk /^State:/ {print $2} 1000 58405 57471 acpiconf -i 1 1000 59201 57471 awk /^Remaining capacity:/ {print $3} 1000 60961 59252 bsdgrep -v -E (COMMAND|idle)$ 1000 63534 59252 head -3 1000 62194 59252 sort -r -n 1000 64629 59252 awk {printf("%s/%d%%/%.1fGB ",$3,$1,$2/1024/1024)} 1000 64634 93198 tail -1 /home/vermaden/.dzen2-fifo

Lots of processes just to update the information on the top of the screen. That is why I refresh dzen2 information only every 5 minutes and if I want exact information and system status for current moment I just ‘click’ on then dzen2 bar to run all these commands and refresh itself.

This way using DTrace you will know if something unwanted does not steal you precious battery time. You may find such dzen2 config in my FreeBSD Desktop – Part 13 – Configuration – Dzen2 article.

Other

ZFS

By default ZFS will commit transaction group every 5 seconds and that is good default setting for the vfs.zfs.txg.timeout parameter. You may want to increase it a little if needed. To 10 for example. I say about that parameter mostly because lots of guides advice to set it to 1 for various performance reasons but keep in mind that setting it to 1 will prevent your disk (and CPU) from going to sleep thus draining more battery life.

If you want to mess with vfs.zfs.txg.timeout value set it in the /boot/loader.conf file.

Applications

To get more time on battery used applications are also crucial. For example Thunar uses less CPU time then Caja or Nautilus. The Geany text editor uses less CPU resources and memory then Scite or Gedit editors, even GVim takes more resouces. Not to mention that custom Openbox/Fluxbox/ ${YOUR_FAVORITE_WM} window manager based setup will consume a lot less CPU time then entire Gnome or Mate environment.

Hardware

It’s sometimes possible to literally buy more battery time. For example when you want to buy new SSD for you laptop then pick not the fastest one but the most power efficient one. You will probably not feel the performance difference anyway but you will appreciate more battery time.

Most RAM modules come with 1.5V current voltage but there is chance that your laptop may support low power DDR modules with 1.35V current thus increasing your battery time. Also keep in mind that each RAM stick uses about 0.5-1.0W of power so using single 8 GB RAM stick will provide you more battery time the the same 8 GB of memory using two 4 GB RAM modules. This also have performance drawback because with single RAM module you will not be able to use dual channel technology so you will limit you RAM speed. Some laptops have even 4 RAM slots (like ThinkPad W520 for example) so without losing anything you should use two 8 GB RAM sticks instead of four 4 GB RAM sticks for longer battery life.

It is sometimes possible to swap your DVD drive to internal secondary battery. Examples of such laptops are Dell Latitude D630, ThinkPad T420s or ThinkPad T500/W500. Sometimes vendors offer entire slice battery that will stick to the bottom of your laptop like slice battery for ThinkPad X220 or T420/T520/W520 laptops or for the 1st generation of ThinkPad X1 laptop.

Hope that this information will help you squeeze some battery time (or at least save some power) on FreeBSD 🙂

UPDATE 1 – Graphics Card Power Saving

If You have the graphics/drm-kmod package installed you probably use the latest i915kms.ko kernel module.

To set maximum power management for integrated Intel graphics cards put these into the /boot/loader.conf file.

# INTEL DRM WITH graphics/drm-kmod PACKAGE (NEW) # SKIP UNNECESSARY MODE SETS AT BOOT TIME compat.linuxkpi.fastboot=1 # USE SEMAPHORES FOR INTER RING SYNC compat.linuxkpi.semaphores=1 # ENABLE POWER SAVING RENDER C-STATE 6 compat.linuxkpi.enable_rc6=7 # ENABLE POWER SAVING DISPLAY C-STATES compat.linuxkpi.enable_dc=2 # ENABLE FRAME BUFFER COMPRESSION FOR POWER SAVINGS compat.linuxkpi.enable_fbc=1

In the past these settings below were used but they are not present anymore.

# INTEL DRM WITH graphics/drm-kmod PACKAGE (OLD) drm.i915.enable_rc6=7 drm.i915.semaphores=1 drm.i915.intel_iommu_enabled=1

UPDATE 2 – AMD CPU Temperatures

While the coretemp(4) kernel module is used for Intel CPUs the amdtemp(4) kernel module will provide additional temperature information for AMD CPUs.

UPDATE 3 – Suspend/Resume Tips

The biggest enemies of supend/resume subsystem are bugs in the BIOS/UEFI firmware. Sometimes disabling the Bluetooth helps – that is the option for the Lenovo ThinkPad T420s for example. On the Lenovo ThinkPad X240 it is disabling the TPM (Trusted Platform Module).

EOF