#+title: AMD GPU support #+setupfile: ../headers #+property: header-args:emacs-lisp :lexical t :exports none :tangle no * AMD GPU support Only one of my machines has an AMD GPU, but it does require some tweaking. First, here’s the skeleton of the =nixos.amdgpu= module. #+begin_src nix :tangle yes { flake.modules.nixos.amdgpu = {pkgs, ...}: { <> <> <> <> <> <> }; } #+end_src ** Enable the Hardware The first thing is to enable graphics in NixOS. We’ll enable 32-bit support while we’re at it. #+name: enable-graphics #+begin_src nix hardware.graphics = { enable = true; enable32Bit = true; }; #+end_src We can now enable the hardware proper, including initrd and OpenCL support for the GPU. =initrd.enable= already makes NixOS load =amdgpu= as early as stage 1 on its own, which is why the kernel module (see [[file:../boot/kernel.org][Kernel Configuration]]) doesn’t need to pick between =amdgpu= and =i915= itself: it can simply default to =i915= and let this module handle its own early loading. #+name: enable-hardware #+begin_src nix hardware.amdgpu = { initrd.enable = true; opencl.enable = true; }; #+end_src Some software expect some packages to be installed by default, such as rocblas or Hipblas. Here are these packages. #+name: amd-packages | Package Name | Description | |----------------------+--------------------------------------------------------------------| | =mesa= | Mesa drivers for AMD GPUs | | =rocmPackages.clr= | Common Language Runtime for ROCm | | =rocmPackages.clr.icd= | ROCm ICD for OpenCL | | =rocmPackages.rocblas= | ROCm BLAS library | | =rocmPackages.hipblas= | HIP BLAS marshalling library (CUDA-compatible interface to rocBLAS) | | =rocmPackages.rpp= | High-performance computer vision library | | =nvtopPackages.amd= | Just for me, GPU utilisation monitoring | #+name: extra-hardware-packages #+begin_src emacs-lisp :var packages=amd-packages :cache yes (mapconcat (lambda (package) (s-chop-prefix "=" (s-chop-suffix "=" package))) (mapcar #'car packages) "\n") #+end_src #+RESULTS[28ba71596b4f184338e46c76c0ba1aa41899bba0]: extra-hardware-packages : mesa : rocmPackages.clr : rocmPackages.clr.icd : rocmPackages.rocblas : rocmPackages.hipblas : rocmPackages.rpp : nvtopPackages.amd #+name: hardware-extra-packages #+begin_src nix hardware.graphics.extraPackages = with pkgs; [ <> ]; #+end_src ** Diagnostics and Monitoring Beyond what’s needed by the driver stack itself, I also want a couple of tools available on the command line to check on the GPU: =clinfo= to inspect the available OpenCL platforms and devices, =amdgpu_top= for a =btop=-like view of the AMD GPU’s activity, and =nvtop= (packaged for AMD under =nvtopPackages.amd=) for a more familiar process-oriented monitor. #+name: system-packages #+begin_src nix environment.systemPackages = with pkgs; [ clinfo amdgpu_top nvtopPackages.amd ]; #+end_src ** LACT, the GPU Control Daemon [[https://github.com/ilya-zlobintsev/LACT][LACT]] (Linux AMDGPU Control Application) lets me tweak fan curves, power limits and clocks on the card, through a daemon (=lactd=) and a GUI that talks to it. The package ships both a systemd service definition and a udev rule, so all that’s left for me to do is install the package and make sure the daemon is started. I’m also consolidating the ROCm libraries under =/opt/rocm= via a =tmpfiles= rule. Some tools out there still expect to find ROCm installed at that standard filesystem location rather than resolved through the Nix store, so I build a combined derivation of the ROCm packages I need and symlink it into place. #+name: lact #+begin_src nix systemd = { packages = with pkgs; [lact]; services.lactd.wantedBy = ["multi-user.target"]; tmpfiles.rules = let rocmEnv = pkgs.symlinkJoin { name = "rocm-combined"; paths = with pkgs.rocmPackages; [ clr clr.icd rocblas hipblas rpp ]; }; in [ "L+ /opt/rocm - - - - ${rocmEnv}" ]; }; #+end_src ** Environment Variables Finally, a handful of environment variables to point tools at that =/opt/rocm= prefix and to steer ROCm/HIP towards the right GPU. This machine exposes the AMD card as device ID =1= (the other device being an iGPU), so I pin both =HIP_VISIBLE_DEVICES= and =ROCM_VISIBLE_DEVICES= to it. The card also isn’t officially supported by ROCm, hence the =HSA_OVERRIDE_GFX_VERSION= override, which tells ROCm to treat it as the closest supported architecture instead of refusing to run. #+name: environment-variables #+begin_src nix environment.variables = { ROCM_PATH = "/opt/rocm"; HIP_VISIBLE_DEVICES = "1"; ROCM_VISIBLE_DEVICES = "1"; HSA_OVERRIDE_GFX_VERSION = "10.3.0"; }; #+end_src