Linux_Ubuntu22.04 _ 安装实时内核补丁PREEMPT_RT
本文详细介绍了在Ubuntu 22.04/24.04系统上安装实时内核补丁PREEMPT_RT的完整过程。首先说明可通过Ubuntu Pro订阅获取官方维护的实时内核,然后分步骤指导手动编译安装:包括下载对应版本的内核源码和RT补丁、安装依赖包、打补丁、配置内核参数(重点设置Fully Preemptible Kernel)、编译安装内核模块、设置用户权限组等关键操作。文章还提供了实时性测试方法,
【Linux / Ubuntu22.04 | 安装实时内核补丁PREEMPT_RT】
前言:
通过
uname -r命令查看当前版本内核,注意:选择自己目前内核最接近的 kernal补丁和RT补丁 并下载,根据其他文章描述在5.15.0-64-generic的基础上,分别安装了5.15.167-rt79和5.10.225-rt117,都是可以正常运行rt内核的,实时性都是OK的。
(Ps: 不过,Ubuntu 提供了 Ubuntu Pro(原 Ubuntu Advantage) 的 实时内核(Real-time Kernel) 支持,从 Ubuntu 22.04 LTS 开始,Canonical 提供了 官方维护的 PREEMPT_RT 内核 作为 Ubuntu Pro 的一项服务(适用于 x86_64 和 ARM64 架构)。当然如果你是Ubuntu Pro 的实时内核需订阅(个人免费使用最多5台设备),可以通过下面命令进行安装,如果你不是那么接下来需要手动编译或从第三方源获取 PREEMPT_RT 补丁)
sudo apt install linux-realtime
1. 准备前工作
查看当前内核版本
uname -a
本文使用环境为Ubuntu 24.04.3 LTS, Linux ttw-MIC-3395 6.8.0-40-generic PREEMPT_DYNAMIC

2.下载内核源码和RT补丁
正常顺序应该是,先查 RT 补丁,再下对应主线程内核源码。
例如,你发现
patch-6.8.2-rt11.patch.xz存在,那就说明 linux-6.8.2.tar.xz 这个主线内核版本有对应的 RT 补丁,可以组合使用
Ps:为什么不建议先下内核再找补丁?:
- RT 补丁并非对所有主线版本都可用,很多主线版本根本没有对应补丁。
- 即使版本接近(如 6.8.2 和 6.8.3),也可能存在不兼容,导致补丁失败或内核不稳定
- RT补丁:https://www.kernel.org/pub/linux/kernel/projects/rt/
- linux内核源码:https://www.kernel.org/pub/linux/kernel
本部使用:
- RT补丁:patch-6.8.2-rt11.patch.xz
- 内核补丁:linux-6.8.2.tar.xz
3.安装依赖
sudo apt update #更新源
sudo apt-get install libncurses-dev libssl-dev build-essential openssl zlibc libelf-dev minizip libidn11-dev libidn11 bison flex zstd
4.解压内核和把RT补丁打进去
sudo mkdir /usr/src/rt_kernal
# 可根据下载位置进行拷贝,当然不复制也没啥~
sudo cp /home/ttw/下载/linux-6.8.2.tar.xz /usr/src/rt_kernal/
sudo cp /home/ttw/下载/patch-6.8.2-rt11.patch.xz /usr/src/rt_kernal/
cd /usr/src/rt_kernal/
sudo su
xz -cd linux-6.8.2.tar.xz | tar xvf -
cd linux-6.8.2
xzcat ../patch-6.8.2-rt11.patch.xz | patch -p1
5.配置内核
- 复制系统当前内核的.config文件(无论当前是哪个内核版本都可以)
cp -v /boot/config-6.8.0-40-generic .config
- 进入图形化界面配置.config文件
make menuconfig # 使用 menuconfig 进行内核配置:
- 需要改动的地方如下:
General Setup -> Timers subsystem -> Timer tick handling 设置为 Full dynticks system
General Setup -> Timers subsystem 开启 High Resolution Timer SupportGeneral Setup -> Preemption Model 设置为 Fully Preemptible Kernel (Real Time)RT
Processor type and features -> Timer frequency 设置为 1000 HZDevice Drivers -> staging drivers 设置为 不开启 ——[ ] 默认开启,按N取消
Ps:理论上只有高亮的两条需要配置其他都是默认的,最后save 保存一下。


6.编辑Config文件
CONFIG_SYSTEM_TRUSTED_KEYS=“”
CONFIG_SYSTEM_REVOCATION_KEYS=“”
CONFIG_DEBUG_INFO=n
不然新内核带debug信息超大



7.编译带RT补丁的内核
其中-j$(nproc)表示使用本机的全部线程数进行编译
Ps: 下面这一条指令是最慢的,CPU内核数越多速度越快,因为是全量编译,
drivers/是最大最耗时的,其次是fs/、net/、kernel/、arch/和sound/。
make -j$(nproc) #编译内核
sudo make INSTSALL_MOD_STRIP=1 modules_install #安装模块
sudo make install #安装内核
8.查看是否成功
cd /boot
ls | grep rt
查看/boot 目录下是否有生成的rt核心,应该包括以下4个文件:
config-6.8.2-rt11
initrd.img-6.8.2-rt11
System.map-6.8.2-rt11
vmlinuz-6.8.2-rt11
如果都有,则重启电脑,(在make install #安装内核完成后)系统将把 “Linux 6.8.2-rt11” 列进 GRUB 菜单第一条(默认启动项)。
reboot
重启后并确认当前内核版本,后缀为rt,就表明你已经完成!
uname -r # uname -a # 也行

9.设置用户权限以使用RT实时调度(关键一步)
为了能够以用户权限调度线程(驱动程序将执行此操作),您需要通过更改/etc/security/limits.conf文件来修改用户的限制
建议为实时用户设置一个组,而不是将固定的用户名写入配置文件:
sudo groupadd realtime
sudo usermod -aG realtime $(whoami)
然后,确认当前文件夹下是否包含以下内容,没有则进行天添加:
sudo vi /etc/security/limits.conf
@realtime soft rtprio 99
@realtime soft priority 99
@realtime soft memlock 204800
@realtime hard rtprio 99
@realtime hard priority 99
@realtime hard memlock 204800
- rtprio : 实时调度的优先级
- priority : 最高调度优先级
- memlock : 是内存锁定的大小,单位为
KB,防止应用程序的内存被交换到磁盘(即锁定内存),从而保证高性能
重新登录或重启(必须!)输入以下指令,结果一致说明配置成功~
ulimit -r # 应输出 99 返回用户的最大实时优先级
ulimit -l # 应输出 204800(单位 KiB)
10.测试实时性
安装rt_test测试工具
sudo apt-get install rt-tests
运行测试 5个线程,线程优先级99,以ns单位显示时间
sudo cyclictest -t 5 -p 99 -N -m
测试结果中各项含义如下
T: 线程
P: 线程优先级
C: 计数器。线程的时间间隔每达到一次,计数器加1
I: 时间间隔为1000微秒(us)
Min: 最小延时(us)
Act: 最近一次的延时(us)
Avg: 平均延时(us)
Max: 最大延时(us)
| 选项 | 中文含义 |
|---|---|
-a CPUSET --affinity=CPUSET |
把测量线程“钉”在指定的一组 CPU 上,按轮询方式分配;如 -a 2 表示所有线程都跑在 CPU 2,-a 3-5,0 表示依次使用 3、4、5、0 号 CPU。 |
-A USEC --aligned=USEC |
把线程的唤醒时间对齐到某个微秒偏移(USEC),减少抖动。 |
-b USEC --breaktrace=USEC |
当延迟超过 USEC 微秒时,向 ftrace 发送“break trace”命令,方便抓异常。 |
-c CLOCK --clock=CLOCK |
选择时钟源:0=CLOCK_MONOTONIC(缺省),1=CLOCK_REALTIME。 |
-d DIST --distance=DIST |
线程之间的时间间隔偏移量,单位微秒,默认 500 μs。 |
-D TIME --duration=TIME |
设定测试持续时长;可加后缀 m(分钟)、h(小时)、d(天)。 |
--latency=PM_QOS |
打开 /dev/cpu_dma_latency 并把给定值写进去,以降低 CPU 睡眠延迟。 |
-F PATH --fifo=PATH |
创建一个命名管道,把运行时统计信息实时写入该管道。 |
-h US --histogram=US |
测试结束后在终端打印延迟直方图;US 为要跟踪的最大延迟(μs)。 |
-H US --histofall=US |
与 -h 类似,但额外增加一列“整体统计”。 |
--histfile=PATH |
把直方图写到指定文件,而不是 stdout。 |
-i INTV --interval=INTV |
每个线程的基准周期,单位微秒,默认 1000 μs。 |
--json=FILENAME |
把最终结果以 JSON 格式写入指定文件。 |
-l LOOPS --loops=LOOPS |
指定循环次数;默认为 0,表示无限循环。 |
--laptop |
省电模式:降低 CPU 频率、减少功耗,实时性能会变差。 |
--mainaffinity=CPUSET |
仅把主线程绑到指定 CPU,不影响测量线程。 |
-m --mlockall |
用 mlockall 锁住所有内存,防止页换入换出。 |
-M --refresh_on_max |
只在出现新的最大延迟时才刷新屏幕,适合低带宽终端。 |
-N --nsecs |
输出结果以纳秒为单位(默认是微秒)。 |
-o RED --oscope=RED |
“示波器模式”,减少冗余输出,每 RED 次采样输出一次。 |
-p PRIO --priority=PRIO |
设置最高优先级线程的优先级值(与调度策略配合使用)。 |
--policy=NAME |
设置测量线程的调度策略:other、normal、batch、idle、fifo、rr。 |
--priospread |
从 -p 指定的优先级开始,依次递减,给每个线程分配不同优先级。 |
-q --quiet |
静默模式,只在退出时打印汇总。 |
-r --relative |
使用相对定时器(相对时间),而非绝对定时器。 |
-R --resolution |
检测并打印时钟分辨率(大量调用 clock_gettime)。 |
--secaligned [USEC] |
把线程唤醒对齐到下一秒,并可加微秒偏移。 |
-s --system |
用传统的 nanosleep/setitimer 系统调用,而非 POSIX 定时器。 |
-S --smp |
“标准 SMP 测试”快捷方式:自动启用 -a、-t 且所有线程同优先级。 |
--spike=TRIGGER |
记录所有超过 TRIGGER 微秒的延迟尖峰。 |
--spike-nodes=N |
最多记录 N 个尖峰,默认 1024。 |
--smi |
启用 SMI(系统管理中断)计数器(需内核支持)。 |
-t [NUM] --threads=NUM |
启动线程数;不带 NUM 时使用所有在线 CPU 数量;缺省为 1。 |
--tracemark |
当 -b 触发时,向 ftrace 写一个标记事件。 |
-u --unbuffered |
强制无缓冲输出,方便实时处理数据。 |
-v --verbose |
实时打印详细统计:格式 n:c:v 分别表示线程号、计数、延迟值(μs)。 |
--dbg_cyclictest |
打开调试信息,输出内部状态,方便排查问题。 |
-x --posix_timers |
使用 POSIX 定时器(timer_create)而非 clock_nanosleep。 |
11.启动设置
在/etc/default/grub中配置开机自动选择
sudo vi /etc/default/grub
GRUB_TIMEOUT=10 %超时时间,单位s
GRUB_DEFAULT="1>2" %1代表默认启动第2个内核,2代表所启动内核1中的第3个(序号从0开始)
然后更新grub
sudo update-grub
温馨 小提示~
/etc/security/limits.conf只是把 “允许” 的门槛打开:让你指定的用户或组 有权 把线程/进程调度策略设成SCHED_FIFO、SCHED_RR,并把优先级调到 99。
它并不会自动把任何线程的调度策略改成实时。
因此:
-
不调用
pthread_attr_setschedpolicy(..., SCHED_FIFO)(或sched_setscheduler),线程仍然是默认的SCHED_OTHER,优先级固定为 0。 -
只有在你显式设置
SCHED_FIFO/SCHED_RR并给出优先级 99 后,系统才会真正按实时线程来调度它。
给出C/C++ 设置代码
void set_thread_realtime(int priority) {
struct sched_param sp = { .sched_priority = priority };
pthread_setschedparam(pthread_self(), SCHED_RR, &sp);
}
int main(int argc, char *argv[]) {
set_thread_realtime(99); // 99是优先级
}
问题一:无法定位软件包zlibc、libidn11
- zlibc (下载第三个.deb的软件包):http://zlibc.linux.lu/download.html
- libidn11 (选择对应地区的随便一个就可以了,可能算是危险文件,允许下载即可。):https://packages.debian.org/bullseye/amd64/libidn11/download

# 手动安装旧包
sudo dpkg -i zlibc_*.deb libidn11_*.deb
问题二:Mack和依赖问题
情况一:libncurses-dev,版本不对,导致依赖链断裂。
报错如图所示:
下列软件包有未满足的依赖关系: libncurses-dev : 依赖: libtinfo6 (= 6.3-2ubuntu0.1) 但是 6.4+20240113-1ubuntu2 正要被安装 依赖: libncurses6 (= 6.3-2ubuntu0.1) 但是 6.4+20240113-1ubuntu2 正要被安装 依赖: libncursesw6 (= 6.3-2ubuntu0.1) 但是 6.4+20240113-1ubuntu2 正要被安装 E: 无法修正错误,因为您要求某些软件包保持现状,就是它们破坏了软件包间的依赖关系。

Mack 时候报错

解决:
先安装(切换root)
sudo su
apt install aptitude
aptitude install libncurses-dev
点击n采取降级方案,之后输入 Y

正常的话便可以安装了
apt-get install libncurses5-dev
情况二:缺少 flex(或 bison)
报错如图所示:
make[2]: *** [scripts/Makefile.host:9:scripts/kconfig/lexer.lex.c] 错误 127 make[1]: *** [/usr/src/rt_kernal/linux-6.8.2/Makefile:689:menuconfig] 错误 2 make: *** [Makefile:240:__sub-make] 错误 2

说明在生成 lexer.lex.c 时,缺少 flex(或 bison) 这类 词法/语法生成器。直接根据下面命令安装就可以
sudo apt install flex bison
情况三: 补装常见缺失依赖
报错命令如下所示:
compilation terminated. make[5]: *** [/usr/src/rt_kernal/linux-6.8.2/tools/build/Makefile.build:106:/usr/src/rt_kernal/linux-6.8.2/tools/objtool/arch/x86/decode.o] 错误 1 make[4]: *** [/usr/src/rt_kernal/linux-6.8.2/tools/build/Makefile.build:158:arch/x86] 错误 2 make[3]: *** [Makefile:66:/usr/src/rt_kernal/linux-6.8.2/tools/objtool/objtool-in.o] 错误 2 make[2]: *** [Makefile:73:objtool] 错误 2 make[1]: *** [/usr/src/rt_kernal/linux-6.8.2/Makefile:1360:tools/objtool] 错误 2 make: *** [Makefile:240:__sub-make] 错误 2
建议先补充依赖
# 1. 补装常见缺失依赖
sudo apt update
sudo apt install build-essential libncurses-dev bison flex libssl-dev libelf-dev bc
理论上处理完这一步应该就可以编译了
# 2. 如果还是不行就确认一下 gcc 版本
gcc --version # 若 >13,建议切回 11/12
sudo apt install gcc-12 g++-12
export CC=gcc-12 CXX=g++-12
更多推荐


所有评论(0)