ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Ubuntu 18.04 NVIDIA驱动故障排查:nvidia-smi失联与分辨率异常修复

Ubuntu 18.04 NVIDIA驱动故障排查:nvidia-smi失联与分辨率异常修复 写这篇东西的起因是最近连续遇到几台 Ubuntu 18.04 的工作站出现同一个毛病用户早上过来发现屏幕分辨率不对图标和窗口突然变得巨大或者画面超出显示器边界然后终端里敲nvidia-smi就给你一行红字NVIDIA-SMI has failed because it couldnt communicate with the NVIDIA driver。这行报错在 Linux 显卡驱动场景里几乎是“家门不幸”级别的经典故障网上搜 Ubuntu 18.04 显卡驱动相关问题一半以上都跟它沾边。这篇文章我就把这类故障从头到尾拆一遍包含我自己在真实环境里踩坑得到的排查思路、修复命令、以及防止复发的完整方案。无论你是双系统玩家、深度学习环境的维护者还是刚装完 Ubuntu 18.04 准备装 CUDA 的新手照着这篇文章的思路走一遍大概率能把自己从“开机分辨率异常 nvidia-smi 失联”的泥潭里拉出来。1. NVIDIA-SMI has failed 这行红字到底在说什么1.1 一条报错背后的三层依赖链先说结论nvidia-smi不是独立跑在用户态的一个小程序它要正常工作依赖一整条从内核到用户态的链路。这条链大致是三层内核层nvidia、nvidia-modeset、nvidia-drm这几个内核模块必须正确加载并且和当前运行的内核版本匹配。设备层驱动加载成功后系统里会出现/dev/nvidia0、/dev/nvidiactl、/dev/nvidia-modeset等设备节点这是用户态程序与 GPU 通信的入口。用户态库层nvidia-smi通过libnvidia-ml.soNVML 库去和设备节点通信库的版本必须和内核模块版本一致。所以当报错说couldnt communicate with the NVIDIA driver本质是nvidia-smi拿着 NVML 库去访问设备节点时发现对面根本没响应。最常见的原因是内核模块压根没加载或者模块加载了但版本对不上再或者设备节点根本没生成。这三层里任何一层断了nvidia-smi都会甩给你这行经典红字。我见过很多人在这一步就开始盲目重装驱动结果装了三遍还是老样子。其实报错是在告诉你“通信失败”而不是“驱动不存在”所以正确的做法是先体检再动手别一股脑重装。1.2 屏幕分辨率变大为什么会和驱动扯上关系标题里说“屏幕分辨变大”这个现象我解释一下。显卡驱动正常时Xorg 或者 Wayland 显示服务器通过 NVIDIA 驱动读取显示器的 EDID 信息拿到显示器支持的最佳分辨率然后把画面以正确的缩放比例输出。驱动一旦挂掉显示服务器读不到准确的 EDID或者干脆回退到内核的 VESA/fbdev 通用显示驱动这时候分辨率就会掉到比较保守的档位比如 1024x768 或者 800x600。很多用户看到图标、字体巨大化会说“分辨率变大了”实际上是分辨率降低了。还有一种情况是驱动半挂不挂系统选了一个超出物理屏幕尺寸的虚拟显示模式画面被缩放拉伸看起来像是“画面太大超出屏幕”。两种表现虽然路径不同但根子都是同一个NVIDIA 驱动栈没能正常工作显示输出回到了通用模式。所以处理分辨率问题本质上还是处理驱动问题这两件事从来都是连在一起的。1.3 故障现场常见伴随症状根据我在多台机器上看到的案例这类故障通常不会只有nvidia-smi报错一个症状而是带着一串兄弟问题一起出现开机进桌面后明显卡顿窗口拖动不流畅。分辨率选项里找不到显示器的最佳分辨率。lsmod里看不到nvidia相关模块。/proc/driver/nvidia/version文件不存在。执行dmesg | grep -i nvidia能看到NVRM: NVIDIA GPU is wedged或Failed to initialize the NVIDIA kernel module之类的内核日志。这些症状出现的组合方式不太一样但都属于同一个故障家族。有了这个整体认知再往下定位就有的放矢了。2. 动手前先做一轮体检逐层定位驱动栈2.1 第一站内核模块到底加载没有拿到一台出问题的机器我习惯先跑一组“三连命令”看模块状态uname -r lsmod | grep nvidia modinfo nvidia | grep vermagic第一行是确认当前内核版本第二行是看nvidia系列模块有没有被加载。第三行尤其关键vermagic会打印这个驱动模块编译时对应的内核版本如果它和uname -r输出的版本不一致说明驱动模块是为另一个内核编译的——这就是“内核升级后驱动失效”的典型证据。在 Ubuntu 18.04 上这段历史特别容易重演。系统默认的 HWEHardware Enablement内核会不定期升级而 NVIDIA 驱动如果当时没有通过 DKMS 注册模块自动重编译升级完内核重启模块就找不到了。lsmod里干干净净nvidia-smi自然就报出那句经典红字。如果lsmod里能看到nouveau模块也要注意。nouveau 是 NVIDIA GPU 的开源驱动它和官方闭源驱动不能共存。很多时候用户装了官方驱动但没彻底屏蔽 nouveau启动时 nouveau 抢先占用了设备官方驱动模块反而加载失败表现同样是nvidia-smi失联。2.2 第二站设备节点和用户态库是否完整模块加载正常的情况下检查设备节点ls /dev/nvidia*正常环境应该有/dev/nvidia0、/dev/nvidiactl、/dev/nvidia-uvm等。如果/dev/nvidia*一个都没有说明 udev 规则没有生效或者模块确实没加载成功。如果设备节点存在但nvidia-smi依然报错那就得查用户态库了。Ubuntu 上驱动库通常安装在/usr/lib/x86_64-linux-gnu/libnvidia-ml.so.*。可以手动确认一下库文件在不在以及版本号是多少ls -l /usr/lib/x86_64-linux-gnu/libnvidia-ml.so*如果库文件版本和驱动的内核模块版本差得很远也会出现怪异现象nvidia-smi能找到库但跟内核模块握手时版本对不上同样报通信失败。这种情况常见于用户从官网下载了.run安装包装的时候没先卸载 apt 版本导致用户态库和内核模块来自两套不同的驱动。2.3 第三站Xorg 日志里的关键线索分辨率异常这类问题光查驱动本身的日志还不够还得看 Xorg 的日志。Ubuntu 18.04 的 Xorg 日志通常在/var/log/Xorg.0.loggrep -i nvidia /var/log/Xorg.0.log grep -i edid /var/log/Xorg.0.log grep -i depth /var/log/Xorg.0.log重点关注两个方面一是 Xorg 到底有没有加载nvidia驱动模块还是退回了modesetting或者fbdev二是 EDID 读取是否成功。如果日志里看到(EE) NVIDIA(0): Failed to initialize the NVIDIA kernel module那基本可以确认驱动内核模块没有正确工作Xorg 只能走通用路径分辨率自然就乱了。很多人在分辨率异常时直接去改/etc/default/grub加nomodeset参数这其实是个治标不治本的办法。nomodeset只是让内核不做模式设置强制走 BIOS 提供的显示模式分辨率会变得更加有限。它适合用来“先进系统再说”但不是修复驱动的方案。2.4 把版本对不上这类隐藏炸弹挖出来这一步我建议做个版本对账把多个位置的版本信息拉平来看nvidia-smi --version # 如果有输出的话 dpkg -l | grep nvidia # apt 安装的驱动包版本 ls -l /usr/src/ | grep nvidia # DKMS 源码目录会显示版本号对比这几处的版本号是否一致能快速判断是不是混装导致的错乱。在 Ubuntu 18.04 上最容易踩的坑是先通过apt install nvidia-driver-470装了驱动后来又从 NVIDIA 官网下载了NVIDIA-Linux-x86_64-535.xx.run来装 CUDA 配套驱动结果.run安装器检测到已有驱动时会提示卸载但有些用户直接加--no-uninstall或者--force强行装上最后系统里两套驱动的文件混杂在一起出现各种各样的灵异现象。3. 修复实操从卸载残留到驱动重新落地3.1 修复前防翻车准备网络源、依赖包、救援手段重装驱动之前我强烈建议先做三件事能省掉不少返工一是确认系统软件源可用。Ubuntu 18.04 现在已经发布很多年官方源速度可能不稳定建议先把源切到能用的镜像站然后执行sudo apt update确保能顺利拉到依赖包。二是把编译工具链装好sudo apt install build-essential dkms linux-headers-$(uname -r)linux-headers-$(uname -r)这个包尤其重要NVIDIA 驱动模块要在本地编译必须要有和当前内核完全对应的头文件。很多人重装驱动失败就是缺了这个包编译阶段直接报错退出。三是确认自己有没有救急手段。如果是远程服务器请确保 SSH 还能登录、VNC 或者带外管理可用如果是普通桌面机确保即使显卡驱动没装好也至少有办法进 tty 终端操作。因为显卡驱动安装失败时图形界面很可能起不来而所有修复操作都得在命令行完成。3.2 三种驱动安装方式的使用边界Ubuntu 18.04 上装 NVIDIA 驱动主流路线有三条我直接给出使用场景对比安装方式优点缺点适合场景sudo apt install nvidia-driver-XXX集成度高自动处理依赖和 DKMS版本滞后不一定有新驱动新手、追求稳定、不依赖最新 CUDA官网下载.run安装包版本最新可选组件自由需要手动处理依赖、容易残留需要特定 CUDA 版本、追新Ubuntu 自带的“附加驱动”图形工具点几下就能装不适用于服务器无桌面环境桌面用户最省事我个人经验如果只是希望机器能正常显示、能跑nvidia-smiapt装就够了如果是深度学习环境需要和 CUDA 版本严格对应那就老老实实去官网下载对应驱动。但不管哪种方式装之前都要确认系统里没有另一套驱动的残留。3.3 完整重装 NVIDIA 驱动的标准流程下面是我在 Ubuntu 18.04 上经过多次验证的标准修复流程适用场景就是“当前驱动已经半死不活nvidia-smi失联、分辨率异常”。第一步进入纯命令行模式。桌面环境直接 Ctrl Alt F2 或 F3 进入 tty用账号登录。这里不建议在图形界面里操作卸载因为图形界面本身可能正在用驱动卸载时会出各种诡异问题。第二步停掉显示管理器sudo systemctl stop lightdm # Ubuntu 18.04 常见的是 lightdm # 如果是 gdm3sudo systemctl stop gdm3保险起见可以执行sudo systemctl isolate multi-user.target直接切到多用户模式彻底不碰图形界面。第三步卸载现有驱动。如果之前是 apt 装的sudo apt purge nvidia-* -y sudo apt autoremove -y如果之前是.run装的在对应目录下执行sudo sh ./NVIDIA-Linux-x86_64-XXX.xx.run --uninstall.run卸载完最好检查下残留文件ls /usr/lib/x86_64-linux-gnu/ | grep nvidia ls /usr/lib/modules/ | grep nvidia有残留就手动删掉或清空对应目录确保环境干净。第四步屏蔽 nouveau。创建/etc/modprobe.d/blacklist-nvidia-nouveau.confecho -e blacklist nouveau\noptions nouveau modeset0 | sudo tee /etc/modprobe.d/blacklist-nvidia-nouveau.conf然后重建 initramfssudo update-initramfs -u这里多说一句屏蔽 nouveau 必须修改 initramfs 才能真正生效只写 modprobe 配置文件不够。我之前见过有人写了 blacklist 文件但没update-initramfs -u重启后 nouveau 还是照样加载白折腾一圈。第五步重新安装驱动。推荐 apt 方式最不容易出问题sudo apt install nvidia-driver-470 # 把 470 换成你实际需要的版本如果确实需要安装 CUDA 配套驱动再通过官网.run安装。装.run时记得加--dkms参数让驱动模块注册到 DKMS 里这样以后内核升级时模块能自动重编译。第六步update-initramfs -u再跑一次然后重启。3.4 安装完成后必须做的验证动作重启完不要急着高兴按这个顺序验证nvidia-smi如果正常输出显卡型号、驱动版本、显存使用情况恭喜核心链路已经恢复了。接着验证cat /proc/driver/nvidia/version ls -l /dev/nvidia*最后确认图形界面是否恢复正常分辨率。如果桌面起不来检查systemctl status lightdm或者看/var/log/Xorg.0.log里有没有新的报错。有一次我在一台服务器上恢复完驱动后nvidia-smi正常但一进桌面就黑屏后来发现是/etc/X11/xorg.conf里残留了旧的 Device 配置把那一行删除、重新生成 Xorg 配置后就正常了。所以如果碰到“命令行正常、图形界面异常”的情况优先检查 Xorg 配置。4. 分辨率异常的来龙去脉与收尾修复4.1 为什么同一块屏幕会出现分辨率异常驱动恢复正常后分辨率通常会自动回到正常状态因为 Xorg 能通过 NVIDIA 驱动正确读取显示器的 EDID。但有时候驱动本身正常分辨率却依然不对那就可能是另外几种情况。一种情况是显示服务器自己缓存了错误的显示配置。Ubuntu 18.04 桌面版默认的显示配置存储在用户目录下的 monitors.xml 或者通过显示设置持久化如果之前驱动故障时系统写入了一份异常配置即使驱动恢复正常它还是会按旧配置来导致分辨率不对。这种情况建议删掉相关配置让系统重新检测。另一种情况是系统有多个显示输出口驱动恢复后默认输出口选错了。比如明明接的是 HDMI 口系统却把画面输出到了 DVI 或者 DP 口屏幕上要么黑屏要么显示非最佳分辨率。这种情况要在显示设置里手动切换输出口或者用xrandr强制指定。4.2 用 xrandr 手动校准显示参数xrandr 是 Xorg 下的显示配置利器驱动恢复正常后可以用来临时矫正分辨率。先看当前状态xrandr输出里会列出所有检测到的输出口HDMI-1、DP-1、eDP-1 等和它们支持的分辨率。找到你实际接入显示器的那一路比如 HDMI-1然后手动设置xrandr --output HDMI-1 --mode 1920x1080 --rate 60如果系统没列出 1920x1080 这个 mode说明 EDID 读取依然有问题可以尝试用cvt手动生成 modelinecvt 1920 1080 60把 cvt 输出的 modeline 信息拿过来添加为一个新模式xrandr --newmode 1920x1080_60.00 173.00 1920 2048 2248 2576 1080 1083 1088 1120 -hsync vsync xrandr --addmode HDMI-1 1920x1080_60.00 xrandr --output HDMI-1 --mode 1920x1080_60.00命令里的 modeline 参数要用cvt实际输出的值不要照抄网上文章的数字否则会花屏。4.3 把修复状态固定下来的持久化配置xrandr 设置是临时的重启就没了。想持久化Ubuntu 18.04 桌面版最简单的办法是在“设置 - 显示”里设置分辨率系统会写入配置文件。如果你用的是 tty 环境或者轻量窗口管理器可以把 xrandr 命令写进~/.xprofile或者/etc/X11/Xsession.d/下的脚本登录时自动执行。我的习惯是写一个/etc/X11/Xsession.d/55-set-resolution文件xrandr --output HDMI-1 --mode 1920x1080 --rate 60这样每次启动 X 会话都会自动应用这个分辨率。注意文件名开头的数字决定了执行顺序取个 55 这种中间值比较安全避免和系统脚本冲突。5. 同族报错盘点那些搜索框里经常一起出现的兄弟5.1 command nvidia-smi not found工具链整体缺失这行报错和标题的报错不一样它意味着系统里根本找不到nvidia-smi这个命令。常见原因有三种驱动没装成功装了驱动但 PATH 里没有或者装的是精简版驱动没带 NVML 工具。如果驱动确实装了但命令找不到可以先手动全路径执行/usr/bin/nvidia-smi # 或者 find /usr -name nvidia-smi 2/dev/nullUbuntu 上nvidia-smi属于nvidia-utils-XXX包驱动主包装了但工具包缺失时会出现这个问题。解决办法sudo apt install nvidia-utils-470 # 版本要和驱动对应如果所有 nvidia 相关的包都没装那就是驱动安装根本没成功回到第 3 章的重装流程。5.2 couldnt find libnvidia-ml.so库路径与版本错乱报错原文是NVIDIA-SMI couldnt find libnvidia-ml.so library in your system。这个比“command not found”更进一步命令存在但它依赖的共享库找不到。libnvidia-ml.so是 NVML 的核心库安装驱动的用户态工具链时会被放到系统库目录。如果用户为了手动指定 GPU 计算库乱设了LD_LIBRARY_PATH环境变量指向了一个没有这个库的目录就会触发该报错。排查方法env | grep LD_LIBRARY_PATH ldconfig -p | grep nvidia-ml如果ldconfig -p里找不到说明库确实没装好重装nvidia-utils-XXX和libnvidia-compute-XXX即可。如果有输出但版本不对说明混装了不同版本的驱动还是得走卸载重装的老路。5.3 no devices were found / unable to determine device handle设备节点异常no devices were found是另一个高频报错字面意思是 nvidia-smi 没找到可管理的 GPU 设备。这种情况通常是内核模块加载了但设备节点没有正确生成或者 GPU 被别的模块占用了。先看模块状态lsmod | grep nvidia ls /dev/nvidia*如果模块在但设备节点不存在可以试着手动加载 udev 规则驱动设备sudo udevadm trigger sudo udevadm control --reload-rules或者直接手动创建节点临时救急sudo mknod -m 666 /dev/nvidia0 c 195 0 sudo mknod -m 666 /dev/nvidiactl c 195 255注意手动创建设备节点只是应急手段重启后就没了最终还是得确保模块正确加载和 udev 规则正确生效。unable to determine the device handle for GPU 0000:41:00.0这种带 PCI 地址的报错通常也是设备节点层面的问题优先走模块重载和 udev 刷新流程。如果设备节点在、模块也在但 nvidia-smi 依然说 no devices那就要怀疑 GPU 是不是被虚拟化或直通环境占用或者主板 slot 供电不足导致设备掉线。这时候查一下lspci | grep -i nvidia看 GPU 还在不在 PCI 总线上。5.4 双系统与虚拟机场景下的特殊诱因热词里出现了“双系统安装”“虚拟机安装 Ubuntu 18.04”这两个场景我顺手讲一下因为它们容易踩和裸机不一样的坑。双系统场景最大的坑是 Windows 的“快速启动”。Windows 默认开启快速启动时关机并不是真正关机而是把内核会话数据写入休眠文件同时可能没有完全释放硬件设备。这时候如果直接切到 UbuntuNVIDIA 显卡可能处于 Windows 留下的非正常状态驱动加载失败。解决办法是进 Windows把“快速启动”关掉或者用“重启”不是“关机”后切换系统。另外双系统如果开了 Secure BootNVIDIA 闭源驱动模块没签名Linux 内核可能直接拒绝加载这就是为什么很多人装驱动时报模块签名验证失败。解决办法是关闭 Secure Boot或者在签名工具中注册 MOK。虚拟机场景就比较特殊了。普通虚拟机里 nvidia-smi 报错其实是正常的因为虚拟机默认不会直通物理 GPU。想让虚拟机里跑 nvidia-smi需要物理机支持并配置 PCI passthrough显卡直通或者使用 vGPU 方案操作复杂度要高好几个量级。如果你只是在 VirtualBox/VMware 里装了个 Ubuntu 18.04想要 GPU 加速那应该装虚拟机增强工具Guest Additions/VMware Tools而不是折腾 NVIDIA 驱动。6. 防止复发内核升级、驱动更新的一整套护身符6.1 为什么内核一升级NVIDIA 驱动就翻车NVIDIA 闭源驱动的内核模块是“锁定内核 API”的也就是说它是针对特定版本的内核源码编译的。Ubuntu 18.04 的软件源会不定期推送内核安全更新如果新内核安装了但 NVIDIA 模块没有跟着重编译重启加载时就会因为版本不一致而失败。这里必须先理解 DKMS 是干什么的。DKMSDynamic Kernel Module Support是一个模块重编译框架驱动源码装进/usr/src目录后DKMS 会在系统每次安装新内核时自动为新内核编译一份对应的模块。只要驱动是以 DKMS 方式注册的内核升级后模块自动跟上灾难就能避免一大半。检查当前驱动是否注册了 DKMSdkms status如果输出里有nvidia/470.xx.x, 5.4.0-x-generic, x86_64: installed这种记录说明注册成功。如果没有记录说明驱动不是通过 DKMS 安装的每次内核升级都有翻车风险。6.2 DKMS 与内核版本锁定配合使用即使有 DKMS也不能完全高枕无忧。DKMS 重编译需要一个重要前提新内核对应的linux-headers包已经安装。如果你用的是apt升级内核Ubuntu 会自动装头文件但如果你是手动下载内核安装经常忘了装头文件这时候 DKMS 也会失灵。所以我的习惯是升级内核后主动跑一次sudo apt install linux-headers-$(uname -r) sudo dkms autoinstall如果你的环境对内核版本极其敏感比如依赖特定内核来运行某些闭源软件、深度学习的某些底层库可以干脆锁住内核不让它自动升级sudo apt-mark hold linux-image-generic linux-headers-generic这样系统后续做apt upgrade时就不会动内核NVIDIA 驱动自然也不会因为内核升级而失效。想解锁时再apt-mark unhold。不过要注意锁内核意味着以后新内核的安全更新也打不上了取舍要自己做。6.3 保留现场与回滚方案还有一招很实用如果一台机器装驱动特别费劲千万不要在折腾完后把安装包删了。apt方式装的驱动对应的.deb包会自动缓存在/var/cache/apt/archives官网.run安装包最好单独保存到一个固定目录。下次系统出问题时不需要重新下载直接本地重装省时又省心。另外建议每次驱动变动前做一个模块加载状态的“基线快照”uname -r ~/nvidia-baseline.txt lsmod | grep nvidia ~/nvidia-baseline.txt cat /proc/driver/nvidia/version ~/nvidia-baseline.txt出问题后对比基线快照能很快看出是内核版本变了、还是模块加载少了、还是驱动版本被替换了。我在维护多台同型号机器时就是用这个办法排查效率高了很多。再补充一个回滚技巧apt 方式装的驱动可以准确回滚版本。比如当前装的是 535想回滚到 470sudo apt install nvidia-driver-470apt 会卸掉旧版本并安装新版本驱动相关配置一般能平滑迁移。而.run方式想要回滚就很痛苦必须先卸载当前版本再装目标版本中间稍有不慎就进不了图形界面所以我个人在服务器环境里更倾向用 apt 管理驱动。最后说说个人的判断标准碰到 Ubuntu 18.04 的 NVIDIA 驱动问题九成以上不是硬件问题而是模块加载、版本匹配、nouveau 抢占这三件事没理清楚。把这三件事按序排查一遍再决定要不要重装比一上来就重装要靠谱得多。装完驱动之后记得把 DKMS 注册好、内核锁好、关键信息留档这套流程走熟了这台机器基本就能安稳用很久了。
返回列表