免重启解决 NVIDIA-SMI 报错 Driver/library version mismatch
问题背景
服务器在更新 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
这时,就要一点一点地卸载整个驱动了:
- 首先要知道现在 kernel mod 的依赖情况;
- 接着我们从错误信息中知道,
nvidia_modeset
nvidia_uvm
这两个mod
依赖于nvidia
; - 不断向下深挖,找到依赖的源头,先把它们逐个卸载掉。
$ 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_uvm
和 nvidia_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
太棒了,完美解决了问题,可以继续炼丹了。
如果有和我一样的菜鸟朋友,文章中的管道串联的命令实在是太长了,容易把脑袋绕晕!
建议从前往后,逐步递进式增加管道,这样就知道前一步的输出是什么数据格式,下一步要对输入做什么特殊处理等。步步为营,如此一来,我们不光知其然还知其所以然了,后面若是要改命令来适应自己的需求,也有的放矢——知道在哪里添加或改动了。