User-friendly NVIDIA Optimus management

Users of laptops with NVIDIA Optimus are probably aware of some traits of getting it work on Linux:

  1. It is properly supported only in proprietary NVIDIA driver which is not shipped by default with the majority of Linux distributions;
  2. Until recently there was no support for NVIDIA Optimus which allows using your integrated video-card for casual applications and GPU for games and other GPU-heavy processes. This problem is semi-solved with PRIME which is the best case requires to log out and log in back;
  3. NVIDIA GPU consumes a lot of power when it’s not used. So there is no official way to turn it off when it’s not used at least for pre-Turing GPU generations.

As you might already know, NVIDIA finally managed to implement D3 power management of dedicated GPU on Optimus-powered laptops in version 435.xx of their proprietary driver, so #3 is no more relevant.

The problem #2 is also solved in latest drivers by adding support for PRIME Render Offloading which allows rendering GPU heavy applications on GPU and others on the integrated.

Unfortunately, to have all this working your laptop has to meet the requirements:

If your laptop meets the requirements you can enable D3 power management mode, otherwise, you only can enable Nvidia Offloading which without D3 is not that useful on laptops as NVIDIA GPUs consumes a lot of power and drain the battery very fast.

Fortunately, there’s an old time-proved solution of managing external GPU power state: it’s bbswitch. While it is often used together with Bumblebee which is deprecated now in favor of PRIME, nothing is stopping you to use it separately just to turn GPU on/of without need to re-login every time.

I maintain a COPR repo with bbswitch-kmod and bumblebee packages for Fedora, while in Ubuntu bbswitch-dkms is shipped in universe repo.

However it’s not really user-friendly and works only for root:

# tee /proc/acpi/bbswitch <<<OFF
# tee /proc/acpi/bbswitch <<<ON

So I got an idea of making the complete solution consisting of:

  • Daemon for managing bbswitch state running under privileged user;
  • Simple command-line utility that allows manage power state for a user from special group;
  • GUI utility sitting in tray and allowing to do it fith a few mouse clicks and providing a simple GPU utilization monitoring.

And it is finally ready!

  • bbswitchd is a daemon that communicates with bbswitch from the one side, and providing a UNIX socket interface for checking status and turning the GPU on and off for the users from bbswitchd group. For the complete guide please proceed to Initial Configuration section of the official README. The usage is quite simple then, just call bbswitch front-end script with one of the available options:
$ bbswitch
bbswitch
Usage: bbswitch on | off | status
$ bbswitch on     # Turn discrete GPU on
$ bbswitch status # Request current status
ON
$ bbswitch off    # Turn discrete GPU off
  • bbswitch-gui is a PyGTK frontend application that allows to manage dedicated GPU power state as well as see GPU utilization, running processes and loaded kernel modules:

Screenshot of bbswitch-gui

When NVIDIA GPU is turned on, some application may utilize it unintentionally and you won’t be able to turn it off until all applications utilizing the GPU are stopped.

That’s why it is useful to see the list of applications using the GPU and being able to kill any (or all) of them by single click.

Also a nice tray icon will appear allowing you to switch the power state even without launching the window:

Screenshot of bbswitch-gui tray menu

If you have switchroo-control installed, When GPU is in use, your desktop environment may offer to launch an application on it:

Screenshot of GNOME launcher

To launch from console you need to setup environment variables, e.g.:

$ __NV_PRIME_RENDER_OFFLOAD=1 __GLX_VENDOR_LIBRARY_NAME=nvidia glxgears

To use PRIME offload for Vulkan applications:

$ __NV_PRIME_RENDER_OFFLOAD=1 __VK_LAYER_NV_optimus=NVIDIA_only vkmark

All this works in both Wayland and X11.

The most straightforward way to install bbswitchd/bbswitch-gui is to use prebuilt packages from copr for Fedora or PPA for Ubuntu.

For Fedora:

$ sudo dnf copr enable polter/bumblebee
$ sudo dnf install bbswitch-gui

For Ubuntu:

$ sudo add-apt-repository ppa:polter-rnd/bbswitch-gui
$ sudo apt update
$ sudo apt install bbswitch-gui

After package installation please check that your user have been added to bbswitchd group using groups command, and then re-login or reboot the machine to apply it.

For more information please proceed to GitHub page.

Tips & Tricks

To make bbswitch-gui auto-start minimized to tray, one can create a file ~/.config/autostart/io.github.polter-rnd.bbswitch-gui.desktop with the following content (-m option means run minimized):

[Desktop Entry]
Type=Application
Encoding=UTF-8
Name=BBswitch GUI
Comment=GUI tool for managing NVIDIA GPU power states and utilization
Exec=/usr/bin/bbswitch-gui -v -m
Icon=bbswitch-gui
Categories=System;Monitor;Utility;X-GNOME-Utilities;
Keywords=nvidia;bbswitch;optimus;prime;
X-AppInstall-Keywords=nvidia;bbswitch;optimus;prime;
X-GNOME-Keywords=nvidia;bbswitch;optimus;prime;
X-GNOME-UsesNotifications=true

Known issues and workarounds

After logout from GNOME shell with enabled NVIDIA GPU, on next login it will detect it and take in use, thus making it impossible to turn dedicated GPU off.

Workaround is to hide NVIDIA GPU from gnome-shell process while keeping it available for all other processes. It can be solved by creating a fake directory on startup for EGL library configurations which is normally in /usr/share/glvnd/egl_vendor.d:

$ ls /usr/share/glvnd/egl_vendor.d/
10_nvidia.json  50_mesa.json

Then override configuration of org.gnome.Shell@wayland.service user-owned systemd unit:

$ systemctl --user edit org.gnome.Shell@wayland.service

[Service]
ExecStartPre=/usr/bin/mkdir -p /tmp/egl_vendor.d
ExecStartPre=/usr/bin/rm -f /tmp/egl_vendor.d/10_nvidia.json
ExecStartPre=/usr/bin/ln -fs /usr/share/glvnd/egl_vendor.d/50_mesa.json /tmp/egl_vendor.d
Environment=__EGL_VENDOR_LIBRARY_DIRS=/tmp/egl_vendor.d
ExecStartPost=/usr/bin/ln -fs /usr/share/glvnd/egl_vendor.d/10_nvidia.json /tmp/egl_vendor.d

On each gnome-shell startup it will see only 50_mesa.json configuration and only then 10_nvidia.json will appear therefore making it availabe for all other processes.