Skip to main content

CUDA on Nvidia Optimus while keeping Intel GPU for X server

Nvidia Optimus laptops include both a power-efficient Intel GPU and a Nvidia GPU. In this post I describe how to enable CUDA on such a laptop while keeping all Linux graphics on the Intel GPU. Thereby power can be saved during normal usage (as the Intel GPU is more efficient). Furthermore the GPU memory is completely free for the CUDA program (otherwise the X server would consume a non-neglectible amount of GPU memory).

Installing the Nvidia drivers

The drivers packaged by your distribution are set up in such a way that CUDA will only work when running the X server on the Nvidia GPU. When switching the X server to the Intel GPU using prime-select CUDA will stop working.

Instead the driver needs to be installed manually. The most recent version of the driver can be found on Nvidia's ftp server (at the time of this writing 378.09).

To install use:

sudo ./NVIDIA-Linux-x86_64-378.09.run --dkms --no-opengl-files

--dkms registers the kernel module with DKMS so that it is rebuilt when you upgrade your kernel.
--no-opengl-files keeps the X graphics configuration of your computer so that you can continue to use the Intel GPU

The installer will likely complain that the open source nouveau driver is loaded in your system. Simply allow the installer to blacklist this driver. Before you reboot your machine make sure to update your initramfs using sudo update-initramfs -u to make sure the nouveau driver is indeed not loaded. Then reboot your machine and start the installation process again as described above.

After installing the driver make sure to update your initramfs using sudo update-initramfs -u.

Enable the Nvidia devices

To enable the Nvidia devices root rights are necessary. Usually this is performed by the X server. However, as we do not wish the X server to manage our Nvidia device and as our CUDA programs are usually not run as root we need to install nvidia-modprobe.

This tool is a setuid program and can therefore enable the Nvidia devices even when called from an unprivileged CUDA program.

Fortunately nvidia-modprobe is automatically installed when installing the Nvidia driver.

This is described in more detail in the FAQ of the driver.

Conclusion

Afterwards CUDA can be used/installed as usual.

Common Problems

DKMS not working

When using a custom kernel that was compiled on a different machine with fakeroot make-kpkg DKMS is often not working. This is due to a bug in make-kpkg not creating properly portable .deb files. It seems this bug is not being fixed as make-kpkg is obsolete.

Instead .deb packages for the linux kereln can be created using make deb-pkg included in the kernels compilation infrastructure. There shouldn't be any problems with dkms when installing the kernel from these .deb packages.

If this does not fix your problem it is likely that the Nvidia driver does not (yet) support your kernel version. At the time of this writing linux 4.9 is supported by the Nvidia driver 375.26 and higher.

Sources

This solution is inspired by a askubuntu.com question but instead uses nvidia-modprobe to avoid having the X server manage the Nvidia card.

Resilient reverse SSH with systemd

At HKUST every (research) computer science student is equipped with a desktop computer at his office desk. One can even request root-access for the computer / install one's own linux on it.

Unfortunately this comes with the drawback that no incoming network connections are allowed, which makes it quite hard (impossible) to ssh into the computer from outside.

Therefore I will describe a solution which makes sure, that the computer establishes a working reverse ssh connection to some server of your choice as long as the network connection is working.

autossh automatically restarts a ssh connection.
systemd can start autossh at system startup.

Restricted server access

The firewalled computer should for security reasons only access a special and restriced account on the server.

We therefore put the following configuration snippet into /etc/ssh/sshd_config on the server machine.

ClientAliveInterval 30
ClientAliveCountMax 3

Match User limited-reverse_ssh_from_machineX
   #AllowTcpForwarding yes
   #X11Forwarding no
   #PermitTunnel no
   #GatewayPorts no
   AllowAgentForwarding no
   PermitOpen localhost:62222
   ForceCommand echo 'This account can only be used for reverse ssh forwarding of a port'

Then the corresponding user account has to be created:

sudo useradd -m -s /bin/false limited-reverse_ssh_from_machineX

-m creates a homedirectory for the user so we can specify the allowed ssh keys.
-s sets the shell to /bin/false so that the user can actually not issue any commands on the server.

Then add create on the (firewalled) computer a new ssh key which you wish to use to establish the reverse ssh connection:

ssh-keygen -f ~/.ssh/reverse-ssh -t ecdsa

Finally copy ~/.ssh/reverse-ssh.pub to the server /home/limited-reverse_ssh_from_machineX/.ssh/authorized_keys.

Local configuration

First configure the settings for the reverse ssh connection in the ~/.ssh/config as follows:

Host reverse_tunnel
HostName bar
   User    limited-reverse_ssh_from_machineX
   IdentityFile    ~/.ssh/reverse-ssh
   RemoteForward   62222 localhost:22
   ServerAliveInterval     30
   ServerAliveCountMax     3

And then create a systemd service by creating a file /etc/systemd/system/reverse-autossh.service.

[Unit]
 Description=AutoSSH service for a reverse tunnel from foo to bar
 After=network.target

[Service]
 User=leonard
 Environment="AUTOSSH_GATETIME=0"
 ExecStart=/usr/bin/autossh -M 0 -NTq -F /home/leonard/.ssh/config freiburg_reverse_tunnel
 Restart=always
 RestartSec=5min

[Install]
 WantedBy=multi-user.target

You can test if everything works with

sudo systemctl daemon-reload
sudo systemctl start reverse-autossh

Don't forget to enable the systemd service on system start with

sudo systemctl enable reverse-autossh

Usage

To ssh into the (firewalled) computer, you may add the following to your ~/.ssh/config

Host firewalled_computer
    User login_user
    Hostname localhost
    Port 62222
    ProxyCommand ssh -q -W %h:%p yourserver.example.com
    ServerAliveInterval 30
    ServerAliveCountMax 3

Updates

  • 07.11.2016: Add keep alive configuration for ssh, so a broken connection (e.g. due to IP address change of the server) is detected; configure systemd to restart the reverse ssh tunnel if autossh dies unexpectedly.