Linux battery life tuning

Just ran my first serious test of all my Framework/Manjaro battery tuning: getting work done while flying from Boston to Belize–one stopover, a total of 8 hours flight time.

Conditions:

  • Laptop started at its 90% charge limit.
  • No expansion card installed except one USB-C.
  • Wi-fi and bluetooth turned off.
  • Powertop runs auto-tune automatically; Gnome power control set to “Power Saver”.
  • Display most of the way down (which is fine in an airline cabin)

The system showed about 4.7-5W consumption most of the time.

I was basically reviewing a 200 page PDF document, so I wasn’t working the system very hard. I hibernated the system between flights.

After 4 hours of work time (1.5 hrs first flight, 2.5 hrs second flight), the laptop showed 68% charge.

Granted, I would expect a much shorter life if I was working the system harder and running wi-fi, but for offline work in ideal conditions, it looks like 8-10 hours is attainable. Surprised me a bit.


UPDATE
After a major network munge, I reinstalled and updated my Manjaro/GNOME installation. With minimal manual tuning other than “powertop --autotune” (no longer using TLP), I’m now seeing even better battery life. With the power manager set to Power Saver and the backlight at minimal, I’m running 3.5-4.5W on Firefox with 2 tabs, cloud services, and two separate mail clients. Balanced shows 4.5-5.5W. Kernel is 5.15.32-1.

Definitely shouldn’t have trouble making it through my flight to the Grenada Chocolate Festival next week ;- )

12 Likes

I’ve loved watching the information grow in these and other threads to the point where we can get the Framework to sip battery at idle. One thing I’ve been wondering for some time is how we can take advantage of Intel’s configurable TDP to limit battery usage under load. I found this thread that walked us through systemd units for setting limits on wattage through the powercap infrastructure.

Has anyone else played with this to see how it might affect battery usage/performance under load? I’m still saving up for my personal Framework laptop; since I’d like to keep my marriage in tact, I can’t really put my wife’s Framework through the ringer until maybe this weekend. :sweat_smile:

1 Like

While not that, this might be a poor person’s substitute for a TDP limit - a straight up perf limit. :smiley: You’d lose the ability to go fast for brief periods of time but it should be similar for prolonged operation.

1 Like

Thanks for sharing this! I spent just a little bit of time today playing with some system settings. I’m sad to say that I don’t have a complete answer to my original question of how well the powercap framework works, since I was a little perplexed by what turned out to be the tlp defaults. Those of you familiar with intel_pstate, CPUFreq, and powercap will already know everything that I will report here, but novice Linux enthusiasts with a mere 10 years of usage like me may learn something :sweat_smile:

TLDR: I activated the defaults in tlp without realizing that these defaults create strict frequency limits for each threaded process. The good news is, I seemed to get powercap working on my machine. Because of some technicalities, I’m unable to provide a meaningful report on the improvements it provides upon standard tlp.

My stress test and some reading

The Phenomenon

I started out by installing stress-ng and trying to get baseline power statistics with powertop under both a single-core and multicore stress test. To my surprise, I found that the usage did not go above ~12w under these the 6 threaded test, and not above ~10w on the single-core test. I found this baffling since I did not set a percentage limit on max performance, and I’m using the 1135g7 which has a tdp of 28w.

I dug into my settings and confirmed that I did not set the max performance limiting. Yet, when I ran tlp-stat, I was informed that a 50% performance limit was being set.

# reported from tlp-stat
/sys/devices/system/cpu/intel_pstate/min_perf_pct      =   9 [%]
/sys/devices/system/cpu/intel_pstate/max_perf_pct      =  50 [%]
/sys/devices/system/cpu/intel_pstate/no_turbo          =   0
/sys/devices/system/cpu/intel_pstate/turbo_pct         =  47 [%]
/sys/devices/system/cpu/intel_pstate/num_pstates       =  39

# i.e. the second line is equivalently this config:
CPU_MAX_PERF_ON_BAT=50

This seemed to explain why the frequency chart on powertop was not reporting above 1.8GHz for any core throughout either a single or multicore stress test.

Intel P-states

At this point, I wanted to know a bit more about what this intel_pstate thing is doing and how it differs from powercap. Here’s what I found:

…the CPUFreq core uses frequencies for identifying operating performance points of CPUs and frequencies are involved in the user space interface exposed by it, so intel_pstate maps its internal representation of P-states to frequencies too…

So pstate is a fancy version of capping CPU frequency—got it! Further:

Since the hardware P-state selection interface used by intel_pstate is available at the logical CPU level, the driver always works with individual CPUs. Consequently, if intel_pstate is in use, every CPUFreq policy object corresponds to one logical CPU and CPUFreq policies are effectively equivalent to CPUs.

Integrating this quote with what we saw previously, here is what I can surmise.

Tlp by default implements pstate-based CPU frequency limiting. Since this limiting is applied to logical CPUs, this ensures that every thread running on the Framework is running at a capped frequency. Consequently, features like turbo boost and even short term boosts in processing are disabled under battery.

Of course, this does provide power advantages, but at the same time it would be nice if I could let one or two threads go above their pstate limit if it still meant having a relatively low power consumption. This means pesky user applications which use way too many CPU cycles (cough Zoom cough) could continue their decadent reign without impacting the user experience.

Researching Powercap

I found this page on the Linux kernel powercap implementation:

[In an example given on the page, t]here is one control type called intel-rapl which contains two power zones, intel-rapl:0 and intel-rapl:1, representing CPU packages. Each of these power zones contains two subzones, intel-rapl:j:0 and intel-rapl:j:1 (j = 0, 1), representing the “core” and the “uncore” parts of the given CPU package, respectively. All of the zones and subzones contain energy monitoring attributes (energy_uj, max_energy_range_uj) and constraint attributes (constraint_*) allowing controls to be applied (the constraints in the ‘package’ power zones apply to the whole CPU packages and the subzone constraints only apply to the respective parts of the given package individually).

From this quote, we may infer that constraints in the powercap framework are applied to the entirety of the CPU. Further, these constraints are a little more dynamic, since they apply to running averages over time rather than instantaneous limits like pstates:

Depending on different power zones, the Intel RAPL technology allows one or multiple constraints like short term, long term and peak power, with different time windows to be applied to each power zone.

So it seems like the application of powercap would allow me to set a similar limit on power usage, e.g. the 12w that I noticed on multicore workloads, without limiting performance on single-core workloads. E.g. no stuttering when launching a big app, container or VM, which might scale up and down quickly without triggering a powercap constraint. In terms of my benchmarks, I would expect this to allow the single-core stress test to go beyond its 1.8GHz limit under tlp while still limiting the multicore stress test.

What I tried

Without messing with the power-prioritizing governor, I tried simply removing the limit on pstate by adding:

CPU_MAX_PERF_ON_BAT=100

Then, I set a TDP target with the powercap-set command:

sudo systemctl stop thermald
sudo powercap-set -p intel-rapl --zone=0 --constraint=0 -l 14000000 -s 10000000
# I had to add this to enable the "core" components of the CPU package
sudo powercap-set -p intel-rapl --zone=0:0 -e 1

I’m essentially using what was reported in the other thread on powercap, linked in my original post. I liked the idea of pinning to the 14W target as the 10-second running average, since this was close to what I got under the default tlp setting of limiting the pstate and @jbch settled on it after their own testing. It seems like powercap goes all the way down to 12W based on the intel specs for the i5 1135g7, although I haven’t tried putting this even lower. I verified that the system accepted these settings with sudo powercap-info -p intel-rapl.

I also played a bit with the energy policy while using the powercap setting:

CPU_ENERGY_PERF_POLICY_ON_BAT=balance_performance

Interestingly, it did seem to have an impact on the metrics for the benchmark, even though the power draw was still limited by powercap. I.e., it seems like powercap might be “smarter” than this energy policy. More tests might be needed to confirm this, though.

What I haven’t done

I haven’t created the systemd scripts to make this setting stick, nor have I verified my conjectures about single-threaded workloads. I’d have to figure out how to get the stress test to “pin” to a specified core, and that’s just a bridge too far for one evening. For the moment, I’m going to give the laptop back to my wife without messing up her battery life, which is already completely amazing to her as it is!

You might have noticed that tlp by default also limits the turbo boost pstate to 47%. It would be interesting to see if I could uncap that as well in combination to gain more performance improvements on battery.

Conclusion

I hope this helps someone out there who is tinkering with their system, or who is trying to figure out how to use Intel’s “TDP-down” configuration in Linux. Let me know if my understanding is wrong, since I may have missed something in my sleuthing! I welcome any thoughts about how to measure CPU frequency under stress testing.

4 Likes

I thought that ~5hours was ok, but now I realized that I should expect something like 10hours.

I did all that was posted here and in other posts on this forum and I cannot get below C3 on idle. The lowest power I managed was ~9W.

I installed powertop and optimized and tlp including PCIE_ASPM_ON_BAT=powersupersave.

OS: KDE neon User - 5.24 x86_64
Kernel: 5.13.0-40-generic

Blacklisting unused SSD expansion cards to save ~1.4W and hit C10

After following all the guides around here, my power consuption was around 5.1 W idle and I only hit C9 but never C10. I found out, that my storage expansion card draws around 1.4W and prevented me from C10. I only use my SSD card to boot Windows, so I decided to blacklist it in my arch install. There is what I did.

This will make your storage card unavailable in your current linux install until you undo this.

1. Find the vendor and product IDs for the card.

~ ❯❯❯ lsusb
Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 003 Device 002: ID 27c6:609c Shenzhen Goodix Technology Co.,Ltd. Goodix USB2.0 MISC
Bus 003 Device 003: ID 8087:0032 Intel Corp. AX210 Bluetooth
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 002: ID 13fe:6500 Kingston Technology Company Inc. USB DISK 3.2
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

We are looking for the ID “13fe:6500”. (Maybe it’s the same for all cards, but please double check.)

2. Create a udev rule to blacklist the device

Change idVendor to the first part of “13fe:6500” and idProduct to the second part.

echo 'SUBSYSTEM=="usb", ATTRS{idVendor}=="13fe", ATTRS{idProduct}=="6500", ATTR{authorized}="0"' | sudo tee /etc/udev/rules.d/01-expansion-ssd.rules

3. Reboot

4. Verifying

Run sudo fdisk -l. The drive should not be listed anymore.

Check powertop. You should now see a lower power usage of around 1.4W and also C10.

Undo

Just remove the udev file and reboot.

sudo rm -f /etc/udev/rules.d/01-expansion-ssd.rules
5 Likes

Thank you for this! I usually keep my expansion cards removed, but it would sometimes be nice to have them installed (e.g. when I’m traveling and just might need USB-A). I worry about losing them if I keep them stored outside the laptop.

I think this is important for the tutorial.

I had a looooooot of problems with BIOS 3.06 and that stupid 92HD95B audio codec.

What does the “Boot performance mode” setting do in the BIOS? There’s an option for “Max battery.” Could that help?

1 Like

Reasonably sure that controls the power state in BIOS?

Should that affect battery life? I could have been imagining things, but it seemed like my power usage was down after turning that on.

You’re imagining things, system overrides it shortly afterwards.

[    0.087028] ENERGY_PERF_BIAS: Set to 'normal', was 'performance'
1 Like

Yeah, I imagined it might be placebo. Do you know if setting the battery charge limit would help? I’m guessing it would with long term battery health.

My understanding is that controls how the system runs while booting, right up until it turns control over to the OS.

1 Like

Has anyone compared tlp and auto-cpufreq? I’ve seen from a reddit thread that auto-cpufreq is actually better. I installed it and removed tlp and seem to be getting lower power consumption.

3 Likes

Sorry for the late response, I don’t frequent the Framework forums. Charge limits ruin runtime, but improve longevity.

1 Like

Anyone tried using something like this to configure TDP instead?

The GPU rendering tips for Firefox (Linux battery life tuning) may be out of date for Firefox 100, at least, according to the linked Arch wiki page (Firefox - ArchWiki).

3 Likes

Hi guys

I got my Framework with i7-1165G7 a few weeks ago. I am running Fedora 36 and was optimizing battery life by replacing PPD with TLP 1.5 (powertop is just used for monitoring).
Configuring TLP with the setting

PCIE_ASPM_ON_BAT=powersupersave

brought idle power consumption down to 2.7W without further tweaks (C8/C10 is entered).
Now I get constant audio crackle (like playing some dusty vinyl) during music playback using headphones or internal speakers running on battery. Putting more load with background applications to the system reduces the crackling. Setting the parameter SOUND_POWER_SAVE_ON_BAT to 0/1/10 has no effect but configuring TLP to

PCIE_ASPM_ON_BAT=performance

removes the audio crackling immediately as well as setting RUMTIME_PM_ON_BAT to on from auto:

PCIE_ASPM_ON_BAT=powersupersave
RUMTIME_PM_ON_BAT = on

I think these settings block the system to enter higher C-states resulting in few watt higher power consumption. Any ideas how to solve this? Now I have to trade battery life for audio quality. :pensive:

Thanks!

1 Like

THIS IS VERY VERY VERY IMPORTANT

I WOULD HAVE SAVED DAYS OF WORK IF I WOULD KNOW ABOUT THAT

PLEASE PUT THIS INTO TUTORIAL

https://wiki.archlinux.org/title/Power_management#PulseAudio

I just found out that the audio codec is fine, the CPU is fine and PulseAudio is a reason for all my troubles with audio and power saving. Because PulseAudio doesn’t go to sleep by default, it keeps the audio codec awake and the codec keeps the CPU in high C states, and all of that wastes ~6W of power.

But I was f* reverse engineering an issue. From CPU through codec to PulseAudio.

And as always, the answer was in Arch wiki.

1 Like