尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Ubuntu实时内核PREEMPT_RT编译安装与NVIDIA显卡驱动修复指南

Ubuntu实时内核PREEMPT_RT编译安装与NVIDIA显卡驱动修复指南 在Ubuntu上给内核打实时补丁PREEMPT_RT本来算是Linux工程师的常规操作但真正让人上头的不是编译过程而是打完补丁重启后桌面进不去——NVIDIA显卡驱动失效了。这个问题我前前后后遇到过好几次也见过不少做EtherCAT主站、运动控制、实时数据采集的同行被卡在同一步。这篇博文就把整条链路完整捋一遍Ubuntu上怎么编译安装实时内核补丁以及安装后NVIDIA显卡驱动挂掉的根本原因和几种靠谱的解决方案。内容偏实操适合做工业控制、机器人、实时以太网主站的Linux开发人员也适合想在Ubuntu上折腾内核又不想被显卡问题劝退的爱好者。先用一句话说清楚这篇文章能帮你解决什么你可以在Ubuntu 20.04/22.04/24.04上从源码编译一个带完整PREEMPT_RT实时特性的内核同时在RT内核上把NVIDIA显卡驱动恢复到可用状态。下面所有步骤和命令都是我实际跑过的不是从文档里抄的踩坑记录也放在后面了。1. 实时内核补丁到底补了什么为什么工控环境离不开它1.1 PREEMPT_RT补丁的核心机制Linux内核默认不是“实时”的这里说的实时不是“响应快”而是“响应时间可预测”。普通内核在运行进程、处理中断、持有锁的时候可能因为各种原因让某个高优先级任务等上几毫秒甚至几十毫秒。对日常服务器、桌面系统来说这个延迟完全无所谓但对EtherCAT主站、运动控制、机器人伺服周期同步来说抖动超过几十微秒就可能直接导致轴抖动、通信丢帧、安全报错。PREEMPT_RT补丁做的事情简单说就是把内核改造成“完全可抢占”的形态。它把内核里不可抢占的临界区尽量缩短把自旋锁替换成可睡眠的rtmutex把中断处理程序线程化让高优先级实时任务可以在几乎任意时刻抢占CPU。加上高精度定时器hrtimer的支持最终目标是让系统的调度延迟稳定在微秒级。有个常见的误解打了RT补丁之后系统会变快。实际上不会RT补丁的代价是牺牲一部分吞吐量换来的是延迟的确定性。所以如果你的应用只是写写代码、跑跑数据库完全没必要上RT内核但如果你在跑IgH EtherCAT主站或者用SOEM做实时通信你会发现普通内核下周期任务的抖动大到离谱而RT内核能把最大延迟压到几十微秒以内这个差距是质变。1.2 什么场景必须用PREEMPT_RT什么场景用lowlatency就够Ubuntu的软件源里其实有一个“低延迟内核”叫做linux-lowlatency很多初学者会混淆。Ubuntu官方对这个内核的描述是优化了交互响应减少延迟但它不是完整的实时内核。lowlatency内核做了部分抢占优化但并没有完整应用PREEMPT_RT补丁因此仍存在不可预测的长延迟点。我给你的选型依据是这样的如果跑EtherCAT主站、实时运动控制、需要硬实时级别的周期同步直接用PREEMPT_RT。如果只是音频录制、普通低延迟交互、桌面流畅度优化lowlatency就够省去编译RT内核的麻烦。如果跑服务器或者普通开发generic内核完全没问题别折腾。我自己用EtherCAT所以选择的是完整的PREEMPT_RT。做工业现场的人应该都知道很多商用主站比如Acontis、KPA甚至明确要求RT内核否则根本不给跑实时周期任务。1.3 为什么很多人选6.6.119这个版本随着内核版本迭代RT补丁的发布和维护有自己独立的节奏。通常RT补丁只跟随LTS长期支持版本比如6.6、6.1、5.15这些分支。6.6.119算是6.6稳定分支里比较新的一个维护版本同时realtime补丁也已经跟进这意味着你可以在6.6这个成熟版本上同时获得稳定性和实时性。还有一个对于工控人来说很重要的点6.6分支里Intel igc网卡驱动对应I225/I226/I227网卡非常稳定而igc网卡配合EtherCAT主站做硬件时间戳同步是一个很常见的方案。我自己的实测感受是6.6.119这个版本编译RT内核后igc网卡在IgH主站下的周期抖动表现比我之前用的5.15分支更好而且不需要额外打别的网卡补丁。所以这篇教程就以6.6.119为例具体方法对6.1、5.15等版本同样适用只是下载对应的源码和补丁时注意版本号要一一对应。2. Ubuntu上从源码编译安装实时内核保姆级步骤2.1 准备工作版本对应、依赖安装、注意事项第一步是下载内核源码和RT补丁文件。内核源码去kernel.org下载对应版本比如linux-6.6.119.tar.xz。RT补丁在kernel.org的projects/rt目录下文件名类似patch-6.6.119-rtX.patch.gz请选择与你下载的内核源码完全相同的版本号。这是一个非常容易踩坑的地方源码版本和补丁版本不一致patch就失败而且失败信息有时候很模糊新手根本看不懂。依赖安装直接用aptsudo apt update sudo apt install build-essential libncurses-dev flex bison libssl-dev bc dwarves libelf-dev这里重点说几个依赖的作用libncurses-dev是给make menuconfig用的flex和bison是内核编译的语法解析器libssl-dev用于生成内核模块签名dwarves处理BTF信息如果不装某些配置下编译会报BTF相关错误libelf-dev是编译内核模块所必需的。还有两个容易被忽略的准备工作磁盘空间至少准备30GB编译整个内核全量模块大概需要15-20GB加上源码解压和补丁文件留足余量。关闭Secure Boot或者在BIOS里预留好MOK签名流程。RT内核编译出来的模块没有经过签名如果开了Secure Boot启动时会被拒绝加载表现为内核起不来或者模块加载失败。工控机还好很多是自己装的Ubuntu直接关Secure Boot最省心。2.2 打补丁、配置内核菜单解压源码并应用RT补丁tar -xf linux-6.6.119.tar.xz cd linux-6.6.119 gzip -cd ../patch-6.6.119-rtX.patch.gz | patch -p1 --dry-run gzip -cd ../patch-6.6.119-rtX.patch.gz | patch -p1先用--dry-run试打一遍确认没有hunk失败再正式打入。很多教程直接跳过了dry-run这一步结果用户打补丁打到一半报错源码目录就废了还得重新解压。补丁打完之后一般推荐基于当前运行内核的配置来做增量修改这样可以最大限度保留你现有系统的驱动支持cp /boot/config-$(uname -r) .config make olddefconfigolddefconfig会用系统自带配置作为默认值自动选择新版本中新增的配置项比make oldconfig逐条问你效率高得多。然后打开内核配置界面找到实时抢占选项make menuconfig在menuconfig里的路径是General setup - Preemption Model - Fully Preemptible Kernel (Real-Time)。选择这一项之后内核会默认启用CONFIG_PREEMPT_RT。除了这项之外我还建议把时钟频率设为1000Hz位置在Kernel Features - Timer frequency这对实时任务的定时精度有帮助。如果你需要CPU隔离还可以在Kernel Features里打开CPU isolation相关的配置或者等到GRUB阶段再处理。这里有个细节用menuconfig搜索功能可以快速确认配置项。按/输入PREEMPT_RT就能看到依赖关系和当前选中状态避免误选。2.3 编译、安装、改GRUB引导配置完成后开始编译。先看CPU核心数nproc make -j$(nproc)如果你把-j设置成核心数的整数倍比如16核机器用-j16编译6.6内核时内存峰值很容易超过8GB。我的经验是内存16GB的机器-j8最稳内存32GB以上再考虑-j16。如果编译过程中出现killed进程基本都是内存不足降低并发即可。编译过程可能持续20分钟到1小时取决于机器性能。编译完成后sudo make modules_install sudo make install sudo update-grubmake install会自动把新内核和initramfs安装到/boot并更新GRUB默认引导项。重启之前建议先看一眼/boot目录里的vmlinuz文件是不是已经包含新内核版本ls /boot/vmlinuz-*然后重启系统在GRUB菜单里选择新内核。启动后确认一下版本和实时抢占状态uname -a zcat /proc/config.gz | grep PREEMPT_RT如果zcat输出的结果是CONFIG_PREEMPT_RTy说明RT内核已经正常工作。注意有些发行版默认没有启动后挂载configfs导致/proc/config.gz不存在这时候可以看/lib/modules/$(uname -r)/build里的autoconf.h不过Ubuntu一般没问题。到这里RT内核本身已经装好了。但绝大多数人在这时候会面临一个全新的问题NVIDIA显卡驱动失效。3. 打上RT补丁后NVIDIA显卡驱动为什么说挂就挂3.1 根因分析DKMS、驱动构建脚本与PREEMPT_RT的冲突在Ubuntu上安装NVIDIA驱动最常见也最推荐的方式是apt直接装比如sudo apt install nvidia-driver-535这种方式之所以省心是因为Ubuntu把NVIDIA驱动注册成了DKMS模块。DKMS的全称是Dynamic Kernel Module Support它的作用是当系统安装新内核时自动为每个已注册的外部内核模块重新编译确保驱动跟内核版本匹配。听起来很完美对吧问题就出在这里NVIDIA官方驱动对PREEMPT_RT内核的支持并不是无条件的它的DKMS构建脚本在检测到CONFIG_PREEMPT_RT被启用时会主动跳过模块编译或者构建失败。这是官方在一定时期内采取的保守策略——RT内核的非标准锁行为可能引发闭源驱动的不可预期问题NVIDIA不想为这种配置做兼容性担保。所以你会发现装完RT内核重启后dkms status里显示NVIDIA模块处于skip状态或者根本没有对应新内核的记录/lib/modules/$(uname -r)/updates/dkms/目录下没有nvidia.ko文件系统实际加载的是nouveau开源驱动或者连nouveau都没加载图形界面直接起不来nvidia-smi报错“No devices were found”或“Failed to initialize the NVIDIA driver”。我用一个生活化的类比帮你理解DKMS就像是一个自动保养系统每次换了新车机新内核它会自动帮你重新安装配件。但NVIDIA这个配件的官方说明书里写着“遇到改装过引擎的车RT内核不要自动安装”于是保养系统就直接跳过了NVIDIA不管你需不需要。这不是系统坏了也不是驱动被删了只是被主动跳过了。3.2 怎么快速判断驱动是不是因为这个原因挂的在动手修复之前先做几个快速诊断确认问题根因。这个习惯很重要能帮你避免在错误的方向上浪费时间。dkms status ls /lib/modules/$(uname -r)/updates/dkms/ modprobe nvidia journalctl -b | grep -i nvidia | tail -30逐条分析dkms status可以明显看到nvidia模块在新内核下没有构建或者显示skippedls命令查看新内核的dkms目录里有没有nvidia相关ko文件modprobe nvidia如果提示模块不存在或者加载后立即报错基本坐实了RT内核下模块缺失journalctl里的日志通常会有类似“nvidia: module not found”的信息。另外一个判断点是如果你切换到原来没打RT补丁的旧内核启动NVIDIA驱动一切正常那就100%是RT内核与驱动构建的兼容性问题而不是显卡硬件坏了。这里顺便说一下为什么有些人会遇到“两块显卡驱动冲突”的现象。如果你同时有核显比如Intel HD Graphics 630和独显NVIDIART内核起来后nouveau模块可能会先绑定了NVIDIA卡而NVIDIA官方驱动无法加载这时系统里就会出现两个显示设备驱动互相抢占的混乱状态。后面讲解决方案时会提到核显和独显分工是一个更稳的思路。4. 恢复NVIDIA显卡驱动的几条路按推荐程度排4.1 官方runfile安装最直接、最省心的修复方式我最推荐的办法也是我在多个现场环境验证过的使用NVIDIA官方.run安装包在RT内核下手动安装驱动。首先从NVIDIA官网下载对应你显卡型号的驱动.run文件。版本选择上如果你的Ubuntu原本用的是apt的535版本那就下载535系列的最新版这样CUDA运行时兼容性最稳。安装前的清理步骤sudo apt purge nvidia-* sudo apt autoremove然后禁用nouveau。编辑/etc/modprobe.d/blacklist-nouveau.conf写入blacklist nouveau options nouveau modeset0更新initramfssudo update-initramfs -u接下来是关键把当前系统切换到文本模式停掉显示管理器。如果你用的是GDMsudo systemctl stop gdm如果用的是LightDM把gdm换成lightdm。确保当前没有图形界面占着显卡然后执行安装程序chmod x NVIDIA-Linux-x86_64-535.xxx.run sudo ./NVIDIA-Linux-x86_64-535.xxx.run --no-dkms--no-dkms参数的意思是不要注册成DKMS模块直接在当前内核下编译并安装nvidia.ko。NVIDIA的官方安装程序在编译模块时不会像apt的nvidia-dkms包那样检测PREEMPT_RT并跳过它更“一根筋”只要内核源码树完整编译环境和依赖都满足就会把模块编出来并放到/lib/modules/$(uname -r)/kernel/drivers/video下。安装过程中选择No注册DKMS、No运行nvidia-xconfig其他默认即可。装完重启你会发现驱动顺利加载nvidia-smi正常输出桌面也回来了。runfile方式最容易被骂的点是“每次换内核都要重装一遍”。这是事实但对于RT内核这个特定场景它就是最可靠的方案。我的建议是把这个驱动安装包放在/opt或/home下别删。以后每次换新内核重新执行一遍上述流程即可整个过程也就十分钟。4.2 修改DKMS行为尽力保留自动重建能力如果你不想放弃DKMS的自动管理也可以试着“手动绕过”跳过逻辑。这个方法效果因人而异因为不同版本的nvidia-dkms包实现过滤的方式不太一样。先定位到DKMS源码目录ls /usr/src/ | grep nvidia找到类似nvidia-535.xxx.x的目录打开dkms.confsudo nano /usr/src/nvidia-535.xxx.x/dkms.conf重点查看是否有与PREEMPT_RT、RT、EXCLUSIVE相关的过滤条件。有些版本的dkms.conf里会有一个类似BUILD_EXCLUSIVE_KERNEL的配置项它是一段正则表达式用来限制哪些内核允许构建。你可以试着把它注释掉或者改成匹配所有内核的模式然后执行sudo dkms build -m nvidia -v 535.xxx.x -k $(uname -r) --force sudo dkms install -m nvidia -v 535.xxx.x -k $(uname -r) --force如果dkms.conf里没有明显的过滤条件但构建过程仍然报错你需要看详细的构建日志sudo dkms build -m nvidia -v 535.xxx.x -k $(uname -r) --force 21 | tee /tmp/dkms.log很多情况下构建错误发生在NVIDIA驱动的make脚本内部它会自己检测PREEMPT_RT并中止。这时候修改dkms.conf已经不管用了得手动进入源码目录找到对应的构建脚本把检测逻辑绕过或注释掉。这个操作就比较深了我不建议新人碰。方案B的最终效果是如果修改成功DKMS依然能在未来内核更新时自动重建NVIDIA模块这是它的最大优势。但它确实属于“绕过官方限制”可能在某个版本更新后失效也可能在特定内核配置下产生未知问题。我的建议是能跑通就当作福利跑不通就老老实实用runfile方案。4.3 工控现场更稳的方案核显桌面独显计算分离到这里说一点行业内的看法。如果你是做EtherCAT、运动控制、实时采样的我其实更推荐这个思路不要让NVIDIA独显承担桌面显示把显示和实时任务分离。做法很简单BIOS里设置iGPU核显为Primary Display物理显示器接在主板的核显输出口上桌面环境完全跑在Intel核显上Ubuntu自带的i915驱动天然兼容不需要额外折腾NVIDIA独显保留给CUDA计算、深度学习推理、或者纯并行计算任务不参与桌面渲染。这样做的好处非常多首先RT内核的CPU隔离配置可以把实时任务绑到指定核上而桌面显示、GPU驱动中断、DMA操作都在其他核上避免了两者互相干扰其次你完全不用纠结NVIDIA驱动在RT内核下的兼容性只需要保证nvidia-smi能看到设备、CUDA runtime能正常调用就行了——而这一点通过runfile方式一次装好后基本不会再出问题。实测下来对于一台装有Intel核显和NVIDIA独显的工控机这是一个非常舒服的状态EtherCAT周期任务稳定跑在隔离CPU上桌面用核显流畅操作CUDA计算的卡仍然被系统正常识别。两全其美。唯一的代价是你没法用独显给桌面做硬件加速但对工控场景来说这根本不是刚需。我见过不少同行在这个问题上钻牛角尖跟RT内核上的NVIDIA桌面驱动死磕好几天最后发现把显示切到核显半小时问题全解。及时止损也很重要。4.4 备选方案退回lowlatency内核或放弃桌面加速如果上面的方法你都觉得麻烦还有一个退而求其次的选项换成Ubuntu自带的linux-lowlatency内核。sudo apt install linux-lowlatency sudo update-grublowlatency内核没有完整应用PREEMPT_RT补丁但它的延迟表现通常比generic好很多而且对NVIDIA驱动这类闭源模块的兼容性相对友好因为NVIDIA官方对lowlatency内核的处理更接近普通内核。如果你的EtherCAT周期是1ms周期抖动要求不太苛刻lowlatency完全扛得住。只有当时钟同步精度要求极高、或者周期任务抖动经常导致丢包时才需要硬上RT。还有一种极端情况机器没有核显又必须用RT内核但NVIDIA驱动在RT内核下实在搞不定比如某些老型号显卡、某些新版本驱动的兼容性问题。这时候只能退而求其次用纯文本模式开发或者用Xorg的modesetting驱动做基础的2D显示。满足“能看终端、能开编辑器”就行CUDA计算用nvidia-smi确认设备在位远程ssh进去跑命令其实也完全够用。5. 实战踩坑记录与常见问题速查5.1 一次完整的故障修复记录我自己最近一次操作的环境是这样的Ubuntu 22.04主板带Intel I226网卡igc显卡是NVIDIA RTX A2000原本用apt装的nvidia-driver-535。为了跑IgH EtherCAT主站我从源码编译了6.6.119-rt内核编译过程很顺利重启进RT内核后GDM起不来卡在登录界面循环。我先用CtrlAltF3切到tty跑了dkms status看到nvidia模块在6.6.119-rt下是missing状态。又试了modprobe nvidia提示模块不存在。确认问题是RT内核下NVIDIA模块没有编译。接着我按部就班执行apt purge nvidia-*、blacklist nouveau、停gdm、下载官网535.run、加--no-dkms安装。安装过程大概三分钟中间有一个小插曲安装器提示找不到当前内核的源码树因为我的系统里没有装linux-headers-6.6.119-rt。解决办法是sudo apt install linux-headers-$(uname -r)如果apt源里没有这个headers包说明你的内核是从源码安装的需要回到内核源码目录执行make headers_install。让我欣慰的是Ubuntu源里通常有对应headers只是名字带-rt后缀。装完驱动重启nvidia-smi正常识别A2000桌面也回来了。整个修复过程大约二十分钟比第一次踩坑时折腾半天快多了。那次踩坑主要是因为没意识到apt的nvidia包和RT内核的兼容性问题一直在试着更新DKMS、切换GRUB里的旧内核走了不少弯路。5.2 常见问题速查表现象常见原因解决方案重启后卡在tty进不了桌面RT内核下NVIDIA模块未构建用runfile方式重装驱动或切到旧内核启动nvidia-smi报No devices were found模块未加载或nouveau抢占确认nouveau已blacklistmodprobe nvidia手动加载dkms status显示skipped或missingNVIDIA DKMS脚本检测到PREEMPT_RT后跳过尝试修改dkms.conf绕过不成功就换runfile方案内核编译过程中进程被killed内存不足并发行太高降低make -j并发度或增加swap安装runfile时提示kernel source missing缺少linux-headers-$(uname -r)安装对应headers包或用--kernel-source-path指定源码目录更新内核后显卡驱动又失效DKMS未参与或runfile驱动未重新编译换新内核后重新执行一次安装流程RT内核启动时模块被拒绝加载Secure Boot未关闭或MOK签名未注册关闭Security Boot或注册新模块签名有核显和独显时显示输出混乱nouveau与nvidia驱动冲突blacklist nouveauBIOS设核显或独显为主显示5.3 实时性与显卡驱动的验证小技巧驱动修复完成后别忘了验证RT内核和NVIDIA驱动的共存状态这里分享几个我常用的验证方法。实时性验证用rt-testssudo apt install rt-tests sudo cyclictest -t 5 -p 80 -i 1000 -d 0 -l 100000重点关注Max和Avg两个指标。RT内核下Max延迟通常在几十微秒级别如果跑到几百微秒甚至毫秒级需要检查是否有驱动中断干扰或者考虑做CPU隔离。显卡驱动验证分两部分nvidia-smi glxinfo | grep OpenGL renderernvidia-smi能看到设备信息和驱动版本glxinfo确认OpenGL渲染器是NVIDIA而不是llvmpipe软件渲染。如果你像我一样跑EtherCAT还有一个更贴合实际的验证方式把IgH主站程序在RT内核下跑起来观察周期任务的实际周期抖动。我之前的经验是从generic内核切到RT内核后IgH主站在igc网卡上的周期抖动从几百微秒降到几十微秒这个变化是可以用示波器或者主站自带的时间戳清清楚楚看到的。另外一个实用小技巧在GRUB引导参数里做CPU隔离可以显著提升实时任务的稳定性。编辑/etc/default/grub把isolcpus、nohz_full、rcu_nocbs按需加上。比如你的机器有8核希望把核心4-7留给实时任务GRUB_CMDLINE_LINUX_DEFAULTquiet splash isolcpus4-7 nohz_full4-7 rcu_nocbs4-7然后update-grub重启后用taskset把EtherCAT主站进程绑到4-7核上运行。这样桌面显示、NVIDIA驱动中断、网络栈都留在0-3核实时任务和显卡驱动互不干扰。这个方法我在多个现场验证过效果非常明显。最后再分享一个小经验无论你选择哪种方案建议在编译RT内核之前先确认旧内核仍然保留在GRUB菜单里万一新内核起不来或者驱动问题短时间解决不了至少还能切回旧内核正常干活。另外把NVIDIA驱动安装包和RT补丁文件都放在固定目录不要删工控现场的软件环境一旦稳定下来最好别频繁变动。我个人的习惯是每次修复成功之后把所有用到的命令整理成一篇操作记录连同安装包一起归档下次遇到问题直接照着执行省得再踩一遍记忆里的坑。
返回列表