Linux battery life tuning

Honestly, I’d rather spend that time figuring out how to use the EQ that’s built in the codec. Then I would not even need PulseEffects or anything and it would obviously save battery.

Codec has like a 12 band parametric bi-quad EQ

1 Like

Set nvme.noacpi=1 in your grub kernel parameters, which results in s2idle suspend battery life that is similar to “deep” on recent kernels without taking the resume time tradeoff. See here for instructions on changing kernel parameters.

On the first comment above, does the kernel parameter nvme.noacpi=1 only affect on the sleep mode s2idle but not on the sleep mode: deep?

By the way, here is nrp’s comment about the setting on Hacker News.

Following our setup guides for Ubuntu 22.04 and Fedora 36 (https://guides.frame.... | Hacker News

Following our setup guides for Ubuntu 22.04 and Fedora 36 (Framework Laptop - Framework Guides) we see around 0.8%/hour on 11th Gen and around 0.4%/hour on 12th Gen Framework Laptops in s0ix.|

It only effected s2idle deep sleep was unchanged in my tests.

s2idle with noacpi=1: 0.280 W/h
deep sleep noacpi=0: 0.285 W/h
deep sleep noacpi=1: 0.286 W/h

1 Like

Thanks for your test! Your test shows that the s2idle has a little bit better battery life than deep sleep on the parameter nvme.noacpi=1. Good to know it!

1 Like

Well I would consider it still in the realm of margin of error but I did round the s2idle value up to 0.280 so perhaps! :slight_smile:

Hey y’all! Lots of stream of consciousness info coming and too lazy to proofread :), so if something doesn’t make sense please feel free to ask me to clarify.

TLDR:

  • Setting an EPP value of 225 seems to be a nice battery/performance balance, but the Intel P-State driver allows you to set whatever you want from 0-255, so it’s customizable to your needs!
  • Setting a max GPU boost/frequency of 450MHz at first blush seems like a battery sweet spot, but same idea applies here. 100MHz to 1,300MHz. Set whatever fits your needs.
  • I’d currently advise against using power-profiles-daemon if you need anything between EEP values of 255 (power) (PPD power-saver) and 128 (balance_performance) (PPD balanced).

So I got a chance with the long weekend to spend some time diving back into battery life tuning, especially after reading reports of some people getting 8-10 hours of battery with light workloads.

Did a bunch of this and that, and from some short tests, I think it’s very possible now to achieve that. There’s definitely been some kernel improvements since I last did a thorough test back in Sept or whatever, but some things that I didn’t see mentioned, though tangentially touched upon (kudos to the all the effort in this thread!) which I think are gamechangers:

CPU Energy Performance Preference

https://www.kernel.org/doc/html/latest/admin-guide/pm/intel_pstate.html#energy-vs-performance-hints
The Energy Performance Preference (EPP) “knob” is where the most energy savings will come from.

# NOTE: (fish shell allows me to use the `*` wildcard in `cpu*`to affect all cpu number directories
# I'm not sure how to do it succinctly in bash etc., though I know a for loop works
cat /sys/devices/system/cpu/cpu*/cpufreq/energy_performance_available_preferences

As we all probably already know these are the values that can be set:

default performance balance_performance balance_power power

However, from the documentation (and I haven’t seen it mentioned anywhere else! Not TLP nor power-profiles-daemon documentation)

The values we can set can also be numeric (0-255) (most to least performance) (most to least energy use) and written like so (as detailed in the above intel_pstate link):

echo "225" | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/energy_performance_preference

These 4 numbers when written translate like so:

Number EPP
0 performance
128 balance_performance
192 balance_power
255 power

Which translate roughly to these frequency limits:

EPP Number Notes
performance 0 boosts to ~4.0GHz, then stays at ~2.8Ghz. Supposed to boost up to 4.7GHz per specs I think? Eh, this is a thread about optimizing battery life, anyways.
balance_performance 128 boosts to ~3.8GHz, then stays at ~2.8GHz
balance_power 192 boosts to ~3.1GHz, then stays at ~2.8GHz
power 255 limits the CPU frequency to ~1.6GHz. This is noticeably laggy – good for reading, but not for compiling code/“multitasking” etc…

So we can see that there’s definitely some optimization to be had between the most energy efficient power mode (1.6GHz) and the next balance_power mode (2.8GHz).

Generally, more energy is used with higher clock speed, meaning an increase from 1.6GHz to 1.7GHz uses much less energy than 2.8GHz to 2.9GHz. This is why disabling Turbo on battery is likely a good idea. There’s also the argument of consumption between race-to-idle and pace-to-idle, but I’d say with rogue/energy-intensive JavaScript sites (even Reddit with autoplaying video), it’s probably a good idea to cut off the top-end frequency where energy consumption is very high.

I’ve found that setting an EPP value of 225 (between power (255) and balance_power (192)) will limit the frequency to ~2.3GHz. This is noticeably faster than 1.6GHz, less energy consuming than 2.8GHz, and seemingly enough for most tasks. At first blush, it seems optimal for my “on battery” needs. Web browsing/coding/working equates to ~= 5-7W roughly? I haven’t tested thoroughly yet, but will as I plan to work more on battery.

Of importance: power-profiles-daemon got rid of the balance_power mode for now:

So a user has to choose between the slow power mode and the higher energy demand balance_performance mode. Terrible for optimizing battery life.

I recompiled PPD to use power, balance_power, and balance_performance (@me if you want the patch), but ended up just switching to TLP. It doesn’t seem to be in the docs, but it’s possible to set any EPP value from 0-255 like so:

/etc/tlp.conf

# Set Intel CPU energy/performance policies HWP.EPP and EPB:
# performance, balance_performance, default, balance_power, power.
...
CPU_ENERGY_PERF_POLICY_ON_AC=balance_performance
CPU_ENERGY_PERF_POLICY_ON_BAT=225
### Note this value is numeric ^

Also, the same ideas apply to the GPU as well:
/etc/tlp.conf

# Set the min/max/turbo frequency for the Intel GPU.
...
INTEL_GPU_MIN_FREQ_ON_AC=100
INTEL_GPU_MIN_FREQ_ON_BAT=100
INTEL_GPU_MAX_FREQ_ON_AC=1300
INTEL_GPU_MAX_FREQ_ON_BAT=450
INTEL_GPU_BOOST_FREQ_ON_AC=1300
INTEL_GPU_BOOST_FREQ_ON_BAT=450

You can see how limiting GPU max/boost frequencies affect power usage/framerate/performance with this:
http://www.kevs3d.co.uk/dev/shaders/

But the above settings (I haven’t tested long-term yet) seem to have a large impact. With the Mountains (in the sunset) demo:

Limited to 1300MHz I saw usage go up to ~20W. FPS ~18.
Limited to 450MHz I saw usage go up to ~10W. FPS ~55.

Limiting the GPU doesn’t make sense if you need the graphics power, but for just web browsing/coding/etc., it can significantly limit bursts of unwanted battery drain, e.g from website videos/ads. It also may make sense for watching videos, though from what I’ve seen, the GPU already does a good job at clocking down.
Related sidenote: for 1080P video playback I was able to get down to 5.5W on 1% brightness, 75% speakers, wifi/bt on – that’s an actual 10 hours of playback! MPV/VAAPI HW decode. Round down to a solid 8 hours at higher brightness.

Miscellaneous

Specs:
i7-1165G7, 64GB G.Skill 3200Mhz, 2TB SK Hynix P31
Fedora 5.17.11-300.fc36.x86_64 with Sway 1.7
Seems like Sway uses slightly more battery than Gnome 4x, could just be my installation, though, and the tradeoff imo is worth it anyways.


Seeing the reports that Ubuntu 22.04 has low idle usage, I tested it out stock on my system. Idle was very low (down to ~2.4W), and mucking/browsing/clicking around with 1 or 2 tabs in Firefox was about 4-6W, roughly.


It’s been a while since I’ve daily driven Windows, but one can set EPP values there with ThrottleStop.


Lastly a nice tip for those that like to stream music in the background while working:

This plays a YouTube stream in the background with no-video. Uses very little energy – very-much-way-more-less than streaming in a browser, especially with the still :pensive: poor Linux browser VAAPI support.

yt-dlp -q -f 91 -o - "youtube video url, can even be a livestream" | mpv --no-cache --no-video -

I’m curious to see how 12th gen energy usage will compare to 11th gen at the same performance .


Cheers! :melting_face:

16 Likes

@Michael_Wu , fantastic write up! I already have my setup well tuned with tlp, but it’s really nice to know there’s that easy of a knob to tweak…

The P31 SSD really seems to help, I highly recommend anyone shopping for power efficient parts go with that one, despite it’s slightly higher price and lower availability.

1 Like

With deep sleep, I measured a drain of 2.7%/hour overnight a few months ago. Yesterday I switched back to s2idle with nvme.noacpi=1, and I measured the same 2.7%/hour again last night. I can live with that, and I’m thrilled to see it wake up instantly again, but I’m just wondering: Has anyone has seen anything like 0.8%/hour in the wild? Could I get that if I hopped from Manjaro over to Fedora? It’s hard to believe the distro would make such a big difference.

I have 32 GB of RAM and three USB-A cards. I’m guessing the 0.8%/hour was with 8 GB and all USB-C cards.

1 Like

In my case, running Manjaro, 64gb, 4x usb-c, I am typically at less than 10% drain overnight - anywhere from 8-12 hours. I’ll make a note tonight and reply back with more accurate numbers. The drain that I am seeing is on the order of 1%/hour, nowhere near 2.7%/hour.

Update - overnight went from 81% to 73% in 9 hours, so a rate of .89%.

1 Like

Yes, see:

That is with an 11th gen i7, 16Gb, and (most importantly!) all USB-C.

I had this problem too, fixed it by changing the powertop tunable to “bad” for:

Autosuspend for USB device Goodix USB2.0 MISC [Goodix Technology Co., Ltd.]

Tlp on or off made no difference.

I just tested an hour of sleep with the 1135, 8GBx2 RAM, 2x type A, 2x type C cards a loaded up Firefox few other things open, wifi on 0.9% drop in an hour.

Ok, yeah, I ran another experiment last night with my USB-A cards removed, and it came in under 0.8%/hour as advertised with s2idle and nvme.noacpi=1 and the other tweaks in this thread (68% to 62% over 8 hours last night vs. 67% to 45% the previous night).

I’m seeing the same. On my system (i5-1135g7, 32GB, 2x USB-C and 2 slots empty, Fedora 36 with kernel 5.17.11-300) with s2idle and nvme.noacpi=1, I saw a drop of 20% over 28 hours… so roughly 0.71%/hr.

1 Like

Is there a way to monitor one’s battery level and get a graph of battery charge level over time?

I have been wanting this for a while. I have not been able to find it. It would help to answer questions like “when is my battery level going down faster than I think?” and “is my battery too old and not holding a charge?” and many others.

Any suggestions?

Just a PSA, I get very different standby consumption values if I do “sudo systemctl suspend” from command line versus selecting suspend from KDE GUI. The former is the ~.8% per hour that others are reporting, the latter results in somewhere between twice and three times as much. Using s2idle in both cases.

Either way, one my EndeavourOS install, the keyboard backlight gets left on when entering suspend, which I would not consider to be a desirable behavior. I have not spent much time to troubleshoot this, though, as I do not use suspend very often in my daily workloads.

So I think we should standardize on command-line initiated, manually verified keyboard backlight off before lid close when trying to compare suspend power draws.

There used to be something like that for gnome, but I wasn’t able to find something that was distributed as a standard. So I use a script:

#!/usr/bin/env python3
from datetime import datetime
from time import sleep
import argparse

def logpow(n):
    d_old = None
    c_old = None
    while True:
        d = datetime.now()
        D = d.strftime("%Y-%m-%d %H:%M:%S")
        with open('/sys/class/power_supply/BAT1/charge_now','r') as F:
            C = F.read().strip()
        c = int(C)
        if c_old is not None:
            p = (c-c_old)/((d-d_old).total_seconds())*3600*1.54e-5
            print("{}, {}, {:.2f}W".format(D,C,p), flush=True)
        else:
            print("{}, {}".format(D,C), flush=True)
        d_old = d
        c_old = c
        sleep(n)
		
parser = argparse.ArgumentParser(description="log battery charge at regular time intervals")
parser.add_argument("-i","--interval", type=float, default=60, help="log interval in seconds (default 60)")
args = parser.parse_args()
logpow(args.interval)

and redirect the output to a file. You can parse that file and make a graph. It also prints the average power use between two samples, which with 1 minute gaps is pretty reliable. Most of the time, that’s sufficient info for me.

On Fedora 35 with Gnome, the keyboard backlight goes off, as far as I can tell. I usually don’t use the CLI or menu options to suspend though: I usually close the lid or press the power button (briefly).

1 Like

Gnome power statistics, I use it with Fedora 35.

1 Like

For folks who are seeing improvements in battery life during standby after setting the “nvme.noacpi=1” kernel parameter, could you share what SSD you are using and if possible, what version of firmware is running on it?

We’ve worked with Western Digital and found that SN750 with 111110WD and older firmware needs that workaround, but updating to 111130WD and newer does not.

Edit: Also, for folks who are not seeing improvements with “nvme.noacpi=1”, could you also share your SSD and the firmware version on it?

I have the SN750 running 111130WD. Now I’m curious to see what I’ll get if I remove the “nvme.noacpi=1” and leave it in s2idle overnight again.

By the way, you commented in September about working to resolve the drain by USB-A and HDMI cards. Will the 3.08 BIOS finally do that?

Tagging along…Does the 12th gen board have the same issue, or is it fixed?