问题背景

服务器在更新 Nvidia Driver 版本之后,经常会出现驱动或库版本不匹配的问题:

$ nvidia-smi
Failed to initialize NVML: Driver/library version mismatch.

原因分析

这个问题出现的原因是 kernel mod 的 Nvidia Driver 的版本没有更新,一般情况下,重启机器就能够解决,如果因为某些原因不能够重启的话,也有办法 reload kernel mod[^1]

简单来看,就两步:

unload nvidia kernel mod
reload nvidia kernel mod

操作步骤

执行起来就是

sudo rmmod nvidia
sudo nvidia-smi

nvidia-smi 发现没有 kernel mod 会将其自动装载。

但是事情远远不是这么简单,一般情况下都会遇到卸载失败。

$ sudo rmmod nvidia
rmmod: ERROR: Module nvidia is in use by: nvidia_modeset nvidia_uvm

这时,就要一点一点地卸载整个驱动了:

  1. 首先要知道现在 kernel mod 的依赖情况;
  2. 接着我们从错误信息中知道,nvidia_modeset nvidia_uvm 这两个 mod 依赖于 nvidia
  3. 不断向下深挖,找到依赖的源头,先把它们逐个卸载掉。
$ lsmod | awk 'NR==1 || /nvidia/'
Module                  Size  Used by
nvidia_uvm           1126400  2
nvidia_drm             61440  0
nvidia_modeset       1146880  1 nvidia_drm
nvidia              40611840  219 nvidia_uvm,nvidia_modeset
drm_kms_helper        184320  4 mgag200,nvidia_drm
drm                   495616  8 drm_kms_helper,drm_vram_helper,nvidia,mgag200,nvidia_drm,ttm

可见 nvidia 模块被使用了 219 次,由于其还被引用着,无法卸载该模块(类似垃圾回收 Garbage Collection 引用计数),所以我们要先卸载引用模块 nvidia_uvmnvidia_modeset

sudo rmmod nvidia_uvm
sudo rmmod nvidia_modeset

若是上面的卸载命令有报错,则需要用 lsof 命令统计驱动的使用量,如果 Nvidia 的使用 Used by 还没有降到 0,kill 相关进程。

先查看下有哪些进程使用了英伟达相关的驱动 nvidia*,命令如下:

$ sudo lsof -n -w  /dev/nvidia*
COMMAND     PID     USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
nvidia-sm 22785     root    3u   CHR 195,255      0t0  423 /dev/nvidiactl
nvidia-sm 22785     root    4u   CHR   195,0      0t0  424 /dev/nvidia0
nvidia-sm 22785     root    7u   CHR   195,0      0t0  424 /dev/nvidia0
nvidia-sm 22785     root    8u   CHR   195,0      0t0  424 /dev/nvidia0
gnome-she 23252      gdm   13u   CHR 195,255      0t0  423 /dev/nvidiactl
gnome-she 23252      gdm   14u   CHR   195,0      0t0  424 /dev/nvidia0
gnome-she 23252      gdm   15u   CHR   195,0      0t0  424 /dev/nvidia0
python    25891 somebody  mem    CHR 195,255           423 /dev/nvidiactl
python    25891 somebody  mem    CHR   195,0           424 /dev/nvidia0
python    25891 somebody  mem    CHR   234,0           425 /dev/nvidia-uvm
python    25891 somebody    3u   CHR 195,255      0t0  423 /dev/nvidiactl
python    25891 somebody    4u   CHR   234,0      0t0  425 /dev/nvidia-uvm
python    25891 somebody    5u   CHR   195,0      0t0  424 /dev/nvidia0
python    25891 somebody    6u   CHR   195,0      0t0  424 /dev/nvidia0
python    25891 somebody    7u   CHR   195,0      0t0  424 /dev/nvidia0
python    25891 somebody   11u   CHR   195,0      0t0  424 /dev/nvidia0
python    25891 somebody   12u   CHR   195,0      0t0  424 /dev/nvidia0
python    25891 somebody   13u   CHR   195,0      0t0  424 /dev/nvidia0
python    25891 somebody   14u   CHR   195,0      0t0  424 /dev/nvidia0
python    25891 somebody   15u   CHR   195,0      0t0  424 /dev/nvidia0
python    25891 somebody   16u   CHR   195,0      0t0  424 /dev/nvidia0
python    25891 somebody   17u   CHR   195,0      0t0  424 /dev/nvidia0
python    25891 somebody   18u   CHR   195,0      0t0  424 /dev/nvidia0
python    25891 somebody   20u   CHR   195,0      0t0  424 /dev/nvidia0
python    25891 somebody   21u   CHR   195,0      0t0  424 /dev/nvidia0
python    25891 somebody   22u   CHR   195,0      0t0  424 /dev/nvidia0
python    25891 somebody   23u   CHR   195,0      0t0  424 /dev/nvidia0

在我们对这些进程有个初步的了解之后,接着执行下面的命令关闭相关进程。[^2]

sudo lsof -n -w  /dev/nvidia* | tail -n +2 | awk '{print $2}' | sort | uniq | xargs -n 1 kill -9
  • tail -n +2 从第二行开始,跳过上一条命令的 header 部分

    -n, --lines=[+]NUM
    output the last NUM lines, instead of the last 10; or use -n +NUM to output starting with line NUM

  • awk:摘选空格分隔的第二个字段
  • sort, uniq: 先排序再去重
  • xargs, kill:依次调用 kill 杀死进程

再次卸载,这次顺利卸载了~

sudo rmmod nvidia

最后,验证一下 nvidia-smi 是否能正常显示显卡的状态。

$ nvidia-smi
Thu Apr 13 10:30:39 2023
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 515.105.01   Driver Version: 515.105.01   CUDA Version: 11.7     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|                               |                      |               MIG M. |
|===============================+======================+======================|
|   0  Tesla V100-PCIE...  Off  | 00000000:3B:00.0 Off |                    0 |
| N/A   46C    P0    39W / 250W |   1141MiB / 32768MiB |      0%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                                  |
|  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
|        ID   ID                                                   Usage      |
|=============================================================================|
|    0   N/A  N/A     25891      C   python                           1137MiB |
+-----------------------------------------------------------------------------+

Work Perfect 😄

总结

总之,遇到驱动/库版本不匹配问题,若能重启机器,就直接重启解决。不能重启的话,考虑卸载并重新加载内核模块。

若是重启解决不了,则考虑重新装驱动和 nvidia-utils-$version-server,常见的英伟达源的三方库如下:

$ dpkg -l "nvidia*" | grep ^ii
ii  nvidia-compute-utils-515-server  515.105.01-0ubuntu0.18.04.1 amd64        NVIDIA compute utilities
ii  nvidia-cuda-dev                  9.1.85-3ubuntu1             amd64        NVIDIA CUDA development files
ii  nvidia-cuda-doc                  9.1.85-3ubuntu1             all          NVIDIA CUDA and OpenCL documentation
ii  nvidia-cuda-gdb                  9.1.85-3ubuntu1             amd64        NVIDIA CUDA Debugger (GDB)
ii  nvidia-dkms-515-server           515.105.01-0ubuntu0.18.04.1 amd64        NVIDIA DKMS package
ii  nvidia-driver-510-server         515.105.01-0ubuntu0.18.04.1 amd64        Transitional package for nvidia-driver-515-server
ii  nvidia-driver-515-server         515.105.01-0ubuntu0.18.04.1 amd64        NVIDIA Server Driver metapackage
ii  nvidia-kernel-common-515-server  515.105.01-0ubuntu0.18.04.1 amd64        Shared files used with the kernel module
ii  nvidia-kernel-source-515-server  515.105.01-0ubuntu0.18.04.1 amd64        NVIDIA kernel source package
ii  nvidia-profiler                  9.1.85-3ubuntu1             amd64        NVIDIA Profiler for CUDA and OpenCL
ii  nvidia-utils-515-server          515.105.01-0ubuntu0.18.04.1 amd64        NVIDIA Server Driver support binaries
ii  nvidia-visual-profiler           9.1.85-3ubuntu1             amd64        NVIDIA Visual Profiler for CUDA and OpenCL

参考链接

  1. CUDA- Nvidia NVML Driver/library version mismatch
  2. 解决 Driver/library version mismatch | Comzyh 的博客

仅有一条评论

  1. bob bob

    太棒了,完美解决了问题,可以继续炼丹了。
    如果有和我一样的菜鸟朋友,文章中的管道串联的命令实在是太长了,容易把脑袋绕晕!
    建议从前往后,逐步递进式增加管道,这样就知道前一步的输出是什么数据格式,下一步要对输入做什么特殊处理等。步步为营,如此一来,我们不光知其然还知其所以然了,后面若是要改命令来适应自己的需求,也有的放矢——知道在哪里添加或改动了。

添加新评论