Post

Configure GPU Passthrough to LXD Container

I recently got hold of a mini PC with a Nvidia GPU and wanted to get hardware transcoding working with Jellyfin in an LXD container. I have previously done this on my existing mini PC that only has an Intel iGPU and I will show how to do that also.

Make sure you disable Secure Boot in UEFI, as I had issues with having it enabled.

Requirements

  • Ubuntu 22.04
  • Supported Nvidia GPU or Intel iGPU
  • Jellyfin running in an LXD container

Nvidia Configuration

Install Nvidia Drivers & Tools

After much playing I found the best way to get this working is to install using the following.

1
2
sudo apt install nvidia-headless-530
sudo apt install nvidia-utils-530

Restart the computer now.

Configure Jellyfin Container

First you need to discover the PCI address of the GPU. That is done by running the following.

sudo lshw -C display

This will show an output like this.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
  *-display
       description: VGA compatible controller
       product: GP107GL [Quadro P600]
       vendor: NVIDIA Corporation
       physical id: 0
       bus info: pci@0000:01:00.0
       version: a1
       width: 64 bits
       clock: 33MHz
       capabilities: pm msi pciexpress vga_controller bus_master cap_list rom
       configuration: driver=nvidia latency=0
       resources: irq:136 memory:f6000000-f6ffffff memory:e0000000-efffffff memory:f0000000-f1ffffff ioport:e000(size=128) memory:c0000-dffff
  *-display
       description: Display controller
       product: HD Graphics 630
       vendor: Intel Corporation
       physical id: 2
       bus info: pci@0000:00:02.0
       logical name: /dev/fb0
       version: 04
       width: 64 bits
       clock: 33MHz
       capabilities: pciexpress msi pm bus_master cap_list fb
       configuration: depth=32 driver=i915 latency=0 resolution=1920,1080
       resources: irq:135 memory:f5000000-f5ffffff memory:d0000000-dfffffff ioport:f000(size=64)

You can see the PCI address under bus info for the Nvidia GPU is 0000:01:00.0. Now we can configure the jellyfin container. The following commands add the necessary nvidia requirements to the container, add a device named nvidia-gpu and tell it to use the gpu with the PCI address of of 0000:01:00.0. For more information about GPU devices, you can see the LXD documentation.

1
2
3
lxc config set jellyfin nvidia.runtime=true nvidia.driver.capabilities=all
lxc config device add jellyfin nvidia-gpu gpu pci=0000:01:00.0
lxc restart jellyfin

At this point you should only need to sign into Jellyfin and enable hardware transcoding for Nvidia.

You can now test that it is working by running watch -d -n 0.5 nvidia-smi on the LXD host and playing a video that requires transcoding. You will see a process at the bottom running.

Intel Configuration

Install Intel GPU Tools

All you need to do is run

1
sudo apt install intel-gpu-tools

You can check this is working by running the command sudo intel_gpu_frequency and you will see a printout, like below, if successful.

1
2
3
4
cur: 350 MHz
min: 350 MHz
RP1: 350 MHz
max: 1150 MHz

Configure Jellyfin Container

This is much simpler to do than the Nvidia configuration. You should only need to pass through the GPU to the server. The difference here was the requirement to allow access by setting the GID of the video group in the container. All the containers I checked had the video group with the GID or 44. You can check by running

1
lxc exec jellyfin -- grep video /etc/group

The command is as simple as the following. Here I have used intel-gpu as the device name. You can set the name to anything you would like.

1
lxc config device add jellyfin intel-gpu gpu gid=44 pci=0000:00:02.0

The pci address comes from the lshw from above as used in the Nvidia configuration.

You now need to enable Intel transcoding in Jellyfin. To test that it is working, play a video, and on the host run intel_gpu_top. I have tested this and it works to switch between the hardware transcoding.

Testing Passthrough With CUDA Toolkit

If you aren’t using Jellyfin, this will show you how to test the passthrough using Nvidia’s CUDA utilities. First, you will need to install NVIDIA CUDA toolkit.

1
sudo apt install nvidia-cuda-toolkit --no-install-recommends

–no-install-recommends parameter will stop it from installing recommended packages that require a full GUI to be installed.

Now you can clone the Nvidia CUDA samples from github with the following and then change to the bandwidthTest utility sample directory.

1
2
git clone https://github.com/NVIDIA/cuda-samples.git
cd cuda-samples/Samples/1_Utilities/bandwidthTest

You will need to edit the Makefile to point to the correct location for the nvcc binary using your preferred editor. Change the file as shown below.

1
2
3
# Location of the CUDA Toolkit
- CUDA_PATH ?= /usr/local/cuda
+ CUDA_PATH ?= /usr

Now run the command make. I ran into an error when attempting this:

1
2
3
/usr/bin/nvcc -ccbin g++ -I../../../Common -m64 --threads 0 --std=c++11 -gencode arch=compute_50,code=sm_50 -gencode arch=compute_52,code=sm_52 -gencode arch=compute_60,code=sm_60 -gencode arch=compute_61,code=sm_61 -gencode arch=compute_70,code=sm_70 -gencode arch=compute_75,code=sm_75 -gencode arch=compute_80,code=sm_80 -gencode arch=compute_86,code=sm_86 -gencode arch=compute_89,code=sm_89 -gencode arch=compute_90,code=sm_90 -gencode arch=compute_90,code=compute_90 -o bandwidthTest.o -c bandwidthTest.cu
nvcc fatal   : Unsupported gpu architecture 'compute_89'
make: *** [Makefile:324: bandwidthTest.o] Error 1

I had to remove 89 and 90 from the make file and re-ran the make command.

1
2
3
4
5
6
7
# Gencode arguments
ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),armv7l aarch64 sbsa))
SMS ?= 53 61 70 72 75 80 86 87 90
else
- SMS ?= 50 52 60 61 70 75 80 86 89 90
+ SMS ?= 50 52 60 61 70 75 80 86
endif

Once successful in compiling you can run ./bandwidthTest and you will see the following.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[CUDA Bandwidth Test] - Starting...
Running on...

 Device 0: Quadro P600
 Quick Mode

 Host to Device Bandwidth, 1 Device(s)
 PINNED Memory Transfers
   Transfer Size (Bytes)        Bandwidth(GB/s)
   32000000                     6.4

 Device to Host Bandwidth, 1 Device(s)
 PINNED Memory Transfers
   Transfer Size (Bytes)        Bandwidth(GB/s)
   32000000                     6.6

 Device to Device Bandwidth, 1 Device(s)
 PINNED Memory Transfers
   Transfer Size (Bytes)        Bandwidth(GB/s)
   32000000                     52.9

Result = PASS

NOTE: The CUDA Samples are not meant for performance measurements. Results may vary when GPU Boost is enabled.

Now to test this, you can copy the bandwidthTest binary to your LXD container, that you have configured passthrough, and run it. Make sure to change “container” to the name of your container when running this command.

1
2
lxc file push ~/cuda-samples/Samples/1_Utilities/bandwidthTest/bandwidthTest container/root/
lxc exec container -- /root/bandwidthTest

If successful, you will see the same printout as above that you ran on the host.

This post is licensed under CC BY 4.0 by the author.