实时系统内核配置与高分辨率定时器详解
在实时系统中,内核的配置和定时器的精度起着至关重要的作用。本文将详细介绍实时内核补丁的配置过程、不同的内核抢占模式以及高分辨率定时器的相关知识。
1. 互斥锁初始化与优先级继承
在多线程编程中,互斥锁是一种常用的同步机制。以下代码展示了如何初始化一个带有优先级继承属性的互斥锁:
if (pthread_mutex_init(&mutex, &attr))
perr("ptherad_mutex_init");
这段代码首先初始化了一个
pthread
互斥锁属性
attr
,并设置了
PTHREAD_PRIO_INHERIT
标志。最后,使用该优先级继承属性初始化互斥锁。由于
futex
优先级继承代码与内核优先级继承中的实时补丁使用相同的代码,因此两者可以很好地协同工作。这意味着,无论高优先级进程是被内核互斥锁阻塞,还是被在用户
futex
上阻塞的低优先级进程阻塞,优先级继承的工作方式都是相同的,并且优先级继承的提升会沿着阻塞进程链向上传递。
2. 使用 RT 补丁配置内核
RT 补丁可以显著提升 Linux 内核的实时性能。以下是使用
ketchup
工具下载和应用 RT 补丁的具体步骤:
1.
创建临时目录并进入
:
~$ mkdir tmp
~$ cd tmp
- 下载 Linux 内核 :
~/tmp$ ketchup -G 2.6.22
-G
选项用于忽略 GPG 校验和,因为我们没有下载任何校验和。此命令会自动从
kernel.org
网站下载 Linux 内核压缩包,并将 Linux 内核树安装到当前目录。
3.
应用 RT 补丁
:
~/tmp$ ketchup -r -G 2.6.22.1-rt9
-r
选项会让
ketchup
在完成安装后将当前目录重命名为安装的 Linux 版本。该命令会先下载并安装
.1
稳定补丁,然后下载并应用
-rt9
版本的 RT 补丁。
4.
显示当前目录
:
~/tmp$ cd .
执行完上述步骤后,
ketchup
会将当前目录重命名为
linux-2.6.22.1-rt9
。
3. 内核配置
下载并应用 RT 补丁后,就可以开始配置内核了。
make menuconfig
构建环境非常灵活,但你也可以使用 Linux 内核自带的其他配置方法。RT 补丁添加了几个选项,其中最重要的是
CONFIG_PREEMPT_RT
,它可以在配置菜单的
Processor type and features → Preemption Mode
中找到。以下是 Linux 内核提供的不同抢占模式:
| 抢占模式 | 描述 | 优点 | 缺点 | 适用场景 |
| ---- | ---- | ---- | ---- | ---- |
| 无强制抢占 | CPU 处于内核模式时不进行抢占,高优先级进程需等待当前进程切换到用户模式或等待 I/O 操作 | 上下文切换最少,开销最小 | 反应时间较慢 | 执行大批量作业的服务器 |
| 自愿内核抢占 | 在已知安全的内核位置插入自愿抢占点,当高优先级进程唤醒且当前进程执行
might_sleep
函数时,可能会触发重新调度 | 提高了内核的交互性和响应性,安全性高 | | 需要一定实时性的场景 |
| 可抢占内核 | 高优先级进程无需等待当前进程进入用户空间或自行调度,当前进程几乎可以在内核的任何位置被调度出 | 显著降低了内核延迟,提升了桌面用户体验 | | 对实时性要求较高的桌面应用 |
| 完全抢占 | 将自旋锁转换为互斥锁,消除了获取自旋锁时对抢占的禁用,使内核响应更快,延迟降低到几微秒 | 极大提高了内核的响应性 | 可能会增加一些调度开销 | 对实时性要求极高的场景 |
下面是这些抢占模式的选择流程 mermaid 图:
graph LR
A[开始] --> B{选择抢占模式}
B --> C[无强制抢占]
B --> D[自愿内核抢占]
B --> E[可抢占内核]
B --> F[完全抢占]
C --> G[适用于批量作业服务器]
D --> H[适用于一定实时性场景]
E --> I[适用于桌面应用]
F --> J[适用于极高实时性场景]
4. 高分辨率定时器
在实时系统中,能够在特定时间触发事件是至关重要的。早期的 Linux 内核(2.6 版本及更早)中,最小的时间单位是
jiffy
,最初
jiffy
是 1/100 秒,对应的
HZ
值为 100。随着机器性能的提升和应用程序的增加,100 HZ 的设置逐渐显得力不从心。为了获得更好的反应时间,
HZ
值提高到了 1000,但即便如此,1 毫秒的最佳反应时间对于真正的实时应用来说仍然不够。
定时器的设计采用了定时器轮(timer wheel),但这种设计存在较大的延迟。当用户应用程序需要在某个时间点得到通知时,事件会被记录到定时器轮中。定时器轮被分成多个“桶”,第一个桶集合(256 个桶)代表未来的 256 个
jiffy
。随着时间的推移,定时器轮中的事件需要重新哈希,这会导致较大的延迟。
为了解决这个问题,Thomas Gleixner 开发了
hrtimers
。
hrtimers
专门为动作定时器(action timers)设计,它使用红黑树来管理事件,避免了定时器轮的重新哈希问题。
hrtimers
的加入,使得定时器的分辨率不再受限于
jiffy
,而是依赖于底层硬件。以下是定时器发展的关键节点:
1.
早期 Linux 内核
:
jiffy
为 1/100 秒,
HZ
值为 100。
2.
性能提升需求
:
HZ
值提高到 1000,但反应时间仍不理想。
3.
定时器轮设计问题
:存在较大延迟,重新哈希开销大。
4.
hrtimers 出现
:专门处理动作定时器,使用红黑树,避免重新哈希。
5.
时钟源基础设施
:定时器不再受限于
jiffy
,分辨率依赖于底层硬件。
综上所述,通过合理配置内核和使用高分辨率定时器,可以显著提升 Linux 系统的实时性能,满足不同场景下的实时需求。在实际应用中,需要根据具体的需求选择合适的内核配置和定时器方案。
实时系统内核配置与高分辨率定时器详解
5. 不同类型定时器的特点与应用
在 Linux 内核的定时器系统中,存在动作定时器(action timers)和超时定时器(timeout timers)两种不同类型的定时器,它们各自有着独特的特点和适用场景。
5.1 动作定时器与超时定时器的区别
- 动作定时器 :这类定时器是用户应用程序为了在特定时间点被通知而设置的,例如闹钟功能。在早期内核中,由于定时器轮的设计,动作定时器每次被添加到较远的未来时都需要进行重新哈希,导致效率低下。
- 超时定时器 :主要用于网络代码中,当数据包未能按时到达时,超时定时器会触发,通知内核发送另一个确认信息。超时定时器需要频繁地添加和删除,因此对添加和删除操作的开销要求极低,定时器轮在这种情况下是一个很好的选择。
5.2 hrtimers 对动作定时器的优化
hrtimers
的出现专门解决了动作定时器在定时器轮中效率低下的问题。它采用红黑树来管理事件,添加和删除节点的时间复杂度为 O(log n),并且能够在 O(1) 时间内找到第一个节点。由于红黑树中的节点是有序的,避免了定时器轮的重新哈希问题,从而显著提高了动作定时器的性能。
以下是一个简单的表格对比定时器轮和 hrtimers 的特点:
| 定时器类型 | 数据结构 | 添加/删除时间复杂度 | 重新哈希问题 | 适用场景 |
| ---- | ---- | ---- | ---- | ---- |
| 定时器轮 | 定时器轮(多个桶) | O(1)(添加和删除) | 有,O(n) 时间开销 | 超时定时器 |
| hrtimers | 红黑树 | O(log n)(添加和删除) | 无 | 动作定时器 |
6. 完全抢占模式下的相关特性
完全抢占模式是 RT 补丁引入的重要特性,它对内核的性能和实时性有着深远的影响。
6.1 自旋锁转换为互斥锁
在完全抢占模式下,自旋锁被转换为互斥锁。自旋锁是一种忙锁,当多个进程竞争时,会导致一个 CPU 处于忙循环状态等待锁的释放。而互斥锁则允许进程在获取锁失败时进入睡眠状态,让内核调度其他进程运行。当锁被释放时,阻塞的进程会被唤醒,如果它是当前最高优先级的进程,就会抢占当前线程并接管 CPU。
这种转换虽然可能会增加一些锁竞争时的开销,但它消除了获取自旋锁时对抢占的禁用,使得内核的响应性大大提高,延迟降低到几微秒。
6.2 中断和软中断的处理
由于中断和软中断在未转换为线程之前不能进行调度,因此选择完全抢占模式会自动选择将中断和软中断转换为线程的内核特性。中断处理程序和软中断经常使用自旋锁,将自旋锁转换为互斥锁后,为了保证调度的正常进行,中断处理程序和软中断也需要转换为线程。
不过,反过来并不一定需要选择完全抢占模式才能将中断处理程序和软中断设置为线程。在其他抢占模式下,也可以通过配置
Thread Softirqs
和
Thread Hardirqs
选项来实现。
下面是完全抢占模式下相关特性的处理流程 mermaid 图:
graph LR
A[选择完全抢占模式] --> B[自旋锁转换为互斥锁]
B --> C[进程获取锁失败进入睡眠]
C --> D[锁释放,阻塞进程唤醒]
D --> E{是否最高优先级}
E -- 是 --> F[抢占当前线程,接管 CPU]
E -- 否 --> G[继续等待]
A --> H[自动选择中断和软中断转线程]
7. 实时系统配置的综合考虑
在配置实时系统时,需要综合考虑内核的抢占模式、定时器类型以及其他相关特性,以满足不同应用场景的实时需求。
7.1 根据应用场景选择抢占模式
- 批量作业服务器 :对于执行大批量作业、对实时性要求不高的服务器,可以选择无强制抢占模式,以减少上下文切换和开销,提高处理效率。
- 一般实时性场景 :如果应用程序需要一定的实时性,但对延迟要求不是特别严格,可以选择自愿内核抢占模式,在保证一定响应性的同时,确保系统的安全性。
- 桌面应用 :对于桌面应用,可抢占内核模式能够显著降低内核延迟,提供更好的用户体验,如更流畅的鼠标移动和音频播放。
- 极高实时性场景 :在对实时性要求极高的场景下,如工业控制、航空航天等领域,完全抢占模式是首选,它能够将内核延迟降低到几微秒,满足严格的实时需求。
7.2 定时器的选择与配置
根据应用程序中定时器的使用情况,合理选择定时器类型。如果应用程序中动作定时器较多,应充分利用
hrtimers
的优势;如果超时定时器占主导,则可以继续使用定时器轮。同时,通过配置时钟源基础设施,让定时器的分辨率依赖于底层硬件,进一步提高定时器的精度。
以下是一个简单的实时系统配置选择列表:
1. 确定应用场景的实时性要求。
2. 根据实时性要求选择合适的内核抢占模式。
3. 分析应用程序中定时器的类型,选择合适的定时器方案。
4. 配置时钟源基础设施,提高定时器分辨率。
通过以上综合考虑和配置,可以构建出一个高效、稳定的实时 Linux 系统,满足各种复杂场景下的实时需求。在实际应用中,还需要不断进行测试和优化,以确保系统的性能达到最佳状态。
超级会员免费看
106

被折叠的 条评论
为什么被折叠?



