/nvidia-more-battery

Get battery time back by making usage of nvidia GPU optional for systems with Optimus

Primary LanguagePythonMIT LicenseMIT

nvidia-more-battery

Get battery time back by making usage of nvidia GPU optional for systems with Optimus

Tests Code style: flake8 Code Analysis: mypy Tox Versions NVIDIA systemd Python

Simply disable dGPU

References

Nvidia Driver References

Run it

First install pdm. See https://pdm-project.org/latest/#recommended-installation-method.

$ pdm create

$ pdm enable  # create the tmpfiles.d file to "enable" the feature; reboot required
$ pdm disable  # remove the tmpfiles.d file and cause the pci bus to be rescanned; NO reboot required
$ pdm has_nvidia

Approach

The approach taken by the code in this project is outlined in the Linux on the ASUS ROG Zephyrus G14 2021 blog post linked to above.

It is based on some work by the ASUS Linux project.

Instead of blacklisting drivers, it leverages the systemd tmpfiles.d infrastructure to disable the hardware by setting a 1 value in the "remove" file for each device as appropriate.

Note there are other ways to accomplish this on Linux without systemd, but it needs to happen early enough in the boot process to influence kernel behavior.

The thing that is so nice about this is that the items deconfigured from the PCIe bus can be brought back at runtime, from within user space and without a reboot. Nice.

JS writes:

If you want to get the dGPU back, for example to pass it into a VM, simply rescan the PCIe bus:

echo 1 | sudo tee /sys/bus/pci/rescan

Monitor Power Draw

Since my persoinal goal is improvement of battery life, I thought it important to have a simple way to monitor power drain and battery time remaining.

There is a script (nvidia_more_battery/power_mon.py) to capture some power consumption metrics. It can be executed by:

$ pdm power  # output to stdout

$ pdm power start  # output to /run/no-nvidia/battery_test_start.txt
$ pdm power stop   # output to /run/no-nvidia/battery_test_stop.txt

If your battery is other than BAT1, then specify the full path to the uevent file on your system.

$ pdm power stdout /sys/class/power_supply/BAT0/uevent # output to stdout

$ pdm power start /sys/class/power_supply/BAT0/uevent  # output to /run/no-nvidia/battery_test_start.txt
$ pdm power stop /sys/class/power_supply/BAT0/uevent   # output to /run/no-nvidia/battery_test_stop.txt

Sample output

{
  "timestamp": "2024-03-10T06:04:39.220894",
  "source": "/sys/class/power_supply/BAT1/uevent",
  "target": "/run/no-nvidia/battery_test_start.txt",
  "power": "1.54 W",
  "energy": "0.38 Ah",
  "draw": "0.09 A",
  "charging": false,
  "capacity": "99%",
  "time_rem": "(252.69) 4 hr(s) 12 mins"
}

Note that I am consistently getting 4 to 4-1/2 hr battery life using this approach.

Scripts

╭────────────┬───────────┬─────────────────────────────────────────────────────────────────╮
│ Name       │ Type      │ Description                                                     │
├────────────┼───────────┼─────────────────────────────────────────────────────────────────┤
│ disable    │ shell     │ Disable nvidia limiting feature and rescan PCI bus; no reboot   │
│ enable     │ shell     │ Enable nvidia limiting feature; reboot is required              │
│ has_nvidia │ composite │ report nvidia is available or not - outputs nvidia or no-nvidia │
│ power      │ cmd       │ python -m ${NVB}.power_mon                                      │
╰────────────┴───────────┴─────────────────────────────────────────────────────────────────╯

TODO

  • Remove nvidia devices from PCI bus
  • [-] Fan profile
  • [-] Battery charge threshold