Get proper battery life on Linux laptops with NVIDIA RTX GPUs.
TL;DR: By default, NVIDIA GPUs stay awake and drain ~6W constantly. This guide enables D3cold power states so the GPU sleeps when idle, doubling battery life on hybrid graphics laptops (tested: 20W → 10W idle).
Linux hybrid graphics laptops with NVIDIA RTX GPUs have terrible battery life out of the box. The GPU never enters deep sleep (D3cold) because:
-
GNOME Shell uses NVIDIA for EGL rendering - libglvnd loads
10_nvidia.jsonbefore50_mesa.json, so the desktop compositor keeps the GPU awake permanently. -
The NVIDIA driver has bugs - Sleep/shutdown hangs, CPU spin bugs, and missing power management features require workarounds.
-
System services keep the GPU awake -
nvidia-persistenced,nvidia-settings, and even Chrome probe the GPU at startup. -
TLP fights against you - Default
RUNTIME_PM_ON_AC=onforces all devices to stay awake on AC power.
git clone https://github.com/jvdillon/rtx-laptop-linux.git
cd rtx-laptop-linux
sudo ./setup.sh
# Reboot requiredThe script will:
- Install NVIDIA drivers (or prompt to reinstall if present)
- Apply all power management fixes
- Configure systemd services for proper sleep/wake handling
libglvnd loads EGL vendors by filename order. Renaming 10_nvidia.json to
90_nvidia.json ensures Mesa (Intel/AMD integrated) loads first.
sudo mv /usr/share/glvnd/egl_vendor.d/{10,90}_nvidia.jsonEven with the priority fix, some apps probe NVIDIA. This environment variable forces Mesa for all desktop rendering:
# /etc/environment
__EGL_VENDOR_LIBRARY_FILENAMES=/usr/share/glvnd/egl_vendor.d/50_mesa.jsonWith modeset=1, nvidia_drm takes over the display, preventing Intel from
driving the panel. This also causes Plymouth hangs during boot.
sudo sed -i 's/modeset=1/modeset=0/' /etc/modprobe.d/nvidia-graphics-drivers-kms.confDriver bug: the nv_open_q kernel thread spins at 20-70% CPU when nonblocking
open is enabled (default).
# /etc/modprobe.d/nvidia-graphics-drivers.conf
options nvidia NVreg_EnableNonblockingOpen=0Reference: NVIDIA/open-gpu-kernel-modules#615
The GPU needs power/control=auto to enter D3cold. This udev rule sets it for
all NVIDIA 3D controllers:
# /etc/udev/rules.d/80-nvidia-pm.rules
ACTION=="add|change|bind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030200", ATTR{power/control}="auto"Driver bug: when the GPU is in D3cold, the driver can't cleanly unload or prepare for system sleep. This causes hangs after "Reached target Reboot" or sleep failures with error -5.
A systemd service wakes the GPU before any shutdown/sleep target:
# /etc/systemd/system/nvidia-wake.service
[Unit]
Description=Wake NVIDIA GPU before shutdown/sleep to prevent hangs
DefaultDependencies=no
Before=shutdown.target reboot.target halt.target suspend.target hibernate.target hybrid-sleep.target
[Service]
Type=oneshot
ExecStart=/bin/bash -c 'echo on > /sys/bus/pci/devices/0000:01:00.0/power/control; sleep 1'
[Install]
WantedBy=halt.target reboot.target shutdown.target suspend.target hibernate.target hybrid-sleep.targetDriver bug: when nvidia modules are in initramfs, they load BEFORE hibernate
resume. The kernel then tries to freeze a freshly-loaded driver that was never
properly initialized, causing pci_pm_freeze(): nv_pmops_freeze returns -5.
Fix: exclude nvidia from initramfs so modules load AFTER hibernate resume.
Ubuntu 25.04+ (dracut):
# /etc/dracut.conf.d/nvidia-exclude.conf
omit_drivers+=" nvidia nvidia-drm nvidia-modeset nvidia-uvm "Ubuntu 24.04 LTS (initramfs-tools):
# /etc/initramfs-tools/hooks/exclude-nvidia
# Hook script that removes nvidia modules from initramfsAlso adds early i915 KMS for external display during LUKS decrypt.
References:
- https://bbs.archlinux.org/viewtopic.php?id=285508
- https://forums.developer.nvidia.com/t/preservevideomemoryallocations-systemd-services-causes-resume-from-hibernate-to-fail/233643
The nvidia driver sets power/control=on when it initializes, and our wake
service sets it before sleep. Both prevent D3cold after boot/resume.
Two systemd units restore power/control=auto:
# /etc/systemd/system/nvidia-power-control.service (after boot)
[Unit]
Description=Enable NVIDIA GPU runtime power management
After=multi-user.target tlp.service
[Service]
Type=oneshot
ExecStart=/bin/bash -c 'echo auto > /sys/bus/pci/devices/0000:01:00.0/power/control'
[Install]
WantedBy=multi-user.target# /etc/systemd/system/nvidia-resume.service.d/restore-pm.conf (after resume)
[Service]
ExecStartPost=/bin/bash -c 'echo auto > /sys/bus/pci/devices/0000:01:00.0/power/control'This service keeps the driver loaded even when the GPU is unused, preventing D3cold. Disabling it enables on-demand loading.
Trade-off: first CUDA call has ~1s latency while the driver loads.
sudo systemctl disable nvidia-persistencedThese official NVIDIA services handle saving/restoring GPU state across suspend and hibernate:
sudo systemctl enable nvidia-suspend nvidia-hibernate nvidia-resumenvidia-settings spawns at login and keeps /dev/nvidia* open, preventing
D3cold.
# ~/.config/autostart/nvidia-settings-autostart.desktop
[Desktop Entry]
Type=Application
Hidden=trueChrome probes /dev/nvidiactl at startup even when not using GPU acceleration.
Force it to use Mesa:
sudo sed -i 's|^Exec=/usr/bin/google-chrome-stable|Exec=env __NV_PRIME_RENDER_OFFLOAD=0 __GLX_VENDOR_LIBRARY_NAME=mesa /usr/bin/google-chrome-stable|' \
/usr/share/applications/google-chrome.desktopTLP defaults to RUNTIME_PM_ON_AC=on which forces all devices awake on AC
power:
sudo sed -i '/^#*RUNTIME_PM_ON_AC/d; $ a RUNTIME_PM_ON_AC="auto"' /etc/tlp.confApply the initramfs changes (nvidia exclusion, early i915):
sudo update-initramfs -u # Ubuntu 24.04
sudo dracut --force # Ubuntu 25.04+After rebooting, verify the GPU enters D3cold when idle:
# Should show "suspended" when GPU is idle
cat /sys/bus/pci/devices/0000:01:00.0/power/runtime_status
# nv_open_q should be ~0% CPU (or not running)
ps aux | grep '\[nv_open_q\]'
# Power draw should be 8-12W idle (without heavy apps)
cat /sys/class/power_supply/BAT*/power_now | awk '{print $1/1000000 " W"}'To wake the GPU for CUDA work:
nvidia-smi # GPU wakes on-demandCheck what's keeping it awake:
# List processes using nvidia devices
sudo fuser -v /dev/nvidia*
# Check if any GL apps are running
lsof /dev/dri/card*Common culprits: Discord, Slack, VS Code (Electron apps), OBS.
The wake service may not be running:
sudo systemctl status nvidia-wake.service
sudo systemctl enable nvidia-wake.serviceCheck if nvidia modules are in initramfs:
lsinitramfs /boot/initrd.img-$(uname -r) | grep nvidiaIf they appear, the dracut config didn't take effect:
sudo update-initramfs -uTry adding to kernel command line:
nvidia.NVreg_PreserveVideoMemoryAllocations=1
Known NVIDIA driver bug (nv_restore_user_channels fails). Use suspend or
hibernate instead - hybrid-sleep is fundamentally broken with these drivers.
The setup script auto-detects your GPU PCI address. The examples in this
README use 0000:01:00.0 for illustration.
To find yours manually:
lspci -D | grep -i nvidia
# Example output: 0000:01:00.0 3D controller: NVIDIA Corporation...If you need to update the systemd services manually, edit:
/etc/systemd/system/nvidia-wake.service/etc/systemd/system/nvidia-power-control.service/etc/systemd/system/nvidia-resume.service.d/restore-pm.conf
For reference, here's how to install the NVIDIA driver and CUDA toolkit on Ubuntu 24.04+:
# Remove any existing nvidia packages
sudo apt purge -y '^nvidia-.*' '^libnvidia-.*' '^cuda-.*' '^libcuda-.*'
sudo apt autoremove -y
# Add NVIDIA CUDA repository
wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2404/x86_64/cuda-keyring_1.1-1_all.deb
sudo dpkg -i cuda-keyring_1.1-1_all.deb
sudo apt update
# Install open driver + CUDA toolkit
sudo apt install -y nvidia-open cuda-toolkit
# Add CUDA to PATH (~/.bashrc)
export PATH="/usr/local/cuda/bin${PATH:+:${PATH}}"
export LD_LIBRARY_PATH="/usr/local/cuda/lib64${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}"To use nsys and other NVIDIA profiling tools without root:
# Allow profiling for all users
echo "options nvidia NVreg_RestrictProfilingToAdminUsers=0" | \
sudo tee /etc/modprobe.d/nvidia-profiling.conf
sudo update-initramfs -u
# Set perf_event_paranoid
echo "kernel.perf_event_paranoid=2" | sudo tee /etc/sysctl.d/99-perf.conf
sudo sysctl -p /etc/sysctl.d/99-perf.conf- NVIDIA Dynamic Power Management
- Arch Wiki: NVIDIA Tips
- Kernel PCI Power Management
- nv_open_q CPU spin bug
- LG Gram Pro 16" 2025 (RTX 5050 Mobile) - Ubuntu 25.10, 25.04
- Ubuntu 24.04 LTS supported (uses initramfs-tools instead of dracut)
- Should work on any hybrid graphics laptop with RTX 20-series or newer
Apache 2.0