实时和 Linux,第 3 部分:子内核和基准测试

作者:Kevin Dankwardt

在本系列的前两篇文章中 [参见 2002 年 1/2 月刊的“实时和 Linux”以及 2002 年 3/4 月刊的“实时和 Linux,第 2 部分:可抢占内核”ELJ],我们探讨了实时的基本概念以及使 Linux 内核更具响应性的努力。在本文中,我们将研究两种实现实时的方法,这两种方法都在硬件和 Linux 之间引入一个单独的、小的实时内核。我们还将回到基准测试,并将桌面/服务器 Linux 内核与修改后的内核进行比较。

我们注意到但不进一步讨论 LynuxWorks 和 OnCore Systems 提供了专有内核,这些内核提供了一些 Linux 兼容性。LynuxWorks 提供了一个实时内核,该内核实现了 Linux 兼容的 API。OnCore Systems 提供了一个实时微内核,该微内核以多种方式提供 Linux 功能。这些内核允许人们在其微内核之上运行 Linux 内核,并使其进程具有实时性能。

在本文中,我们主要关注单 CPU 实时。当使用多个 CPU 时,实时会有新的解决方案。例如,可以避免在等待实时进程的 CPU 上进行系统调用。这完全避免了内核抢占问题。可以将中断定向到特定的 CPU,并远离另一个特定的 CPU,从而避免中断延迟问题。顺便说一句,所有 Linux 实时解决方案都可以在多 CPU 系统上使用。此外,例如 RTAI 还具有用于多 CPU 的附加功能。但是,我们专注于嵌入式 Linux 开发人员的需求,而大多数嵌入式 Linux 设备都只有一个通用 CPU。

什么是实时子内核?

典型的实时系统有几个任务必须以确定性的实时方式执行。此外,通常情况下,对硬件中断的响应必须是确定性的。一个聪明的想法是创建一个小型操作系统内核,该内核提供这些机制,并提供运行 Linux 内核的功能,以提供 Linux 功能的完整补充。

因此,这些实时子内核提供了用于任务处理、中断处理以及与 Linux 进程通信的 API。当子内核的任务运行时或当子内核正在处理中断时,Linux 会被挂起。因此,例如,不允许 Linux 禁用中断。此外,这些子内核不是完整的操作系统。它们没有完整的设备驱动程序。它们不提供广泛的库。它们是 Linux 的补充,而不是独立的操作系统。

然而,随着越来越多的功能被纳入,这些子内核有一种自然的趋势,即从软件版本到软件版本,复杂性不断增加。不过,它们的主要优点是,人们仍然可以在应用程序中利用 Linux 的所有优势。只是应用程序的实时部分由子内核单独处理。

有些人将这种情况视为 Linux 被视为子内核 OS 的最低优先级或空闲任务。图 1 描绘了子内核和 Linux 的关系。

Real Time and Linux, Part 3: Sub-Kernels and Benchmarks

图 1. 子内核和 Linux 的关系

子内核通过三个步骤与 Linux 一起创建:1) 修补 Linux 内核以提供一些用于添加功能等内容的钩子,2) 修改中断处理,以及 3) 创建可加载模块以提供 API 和功能的大部分。

子内核为实时任务提供 API。它们提供的 API 类似于 POSIX 线程、其他 POSIX 函数和附加的唯一函数。使用子内核意味着实时任务正在使用 Linux 程序员可能熟悉的 API,但它们是单独的实现,有时会有所不同。

中断处理通过修补内核源代码树进行修改。例如,这些补丁更改了通常用于禁用中断的函数。因此,当重新编译 Linux 子树中的内核和驱动程序时,它们实际上将无法禁用中断。重要的是要注意此更改,因为它意味着,例如,从这些修改后的标头单独编译的驱动程序实际上可能会禁用中断并阻碍实时技术。此外,非标准代码,例如,简单地内联中断禁用汇编语言指令,也会同样阻碍它。幸运的是,在实践中,这些不太可能发生,当然可以避免。这些例子是为了强调没有真正的实时解决方案是完全没有注意事项的。

RTLinux 和 RTAI

最常用的两个子内核是 RTLinux 和 RTAI。RTLinux 和 RTAI 都是为硬实时设计的。它们不仅仅是一个可抢占内核,而是更多(和稍微少一些)。实际上,实时操作系统为开发人员提供了便利。RTLinux 和 RTAI 提供了大量附加的、与实时相关的功能。例如,除了传统的优先级调度之外,RTAI 还提供速率单调调度和最早截止时间优先调度。

子内核提供 POSIX 和专有函数,以及用于创建任务、禁用/启用中断以及提供同步和通信的函数。当使用 RTLinux 或 RTAI 时,开发人员除了 POSIX 函数之外,还会使用新的 API。

RTLinux 和 RTAI 都为使用用户空间进程提供了一些支持。这很重要,因为 Linux 的实时应用程序自然会想要利用 Linux 的功能。RTLinux 除了可以在内核和用户空间中读取和写入的 FIFO 和共享内存之外,还支持在用户空间进程中调用信号处理程序。RTAI 提供了 FIFO、共享内存和一个完整的硬实时机制 LXRT,可以在用户空间中使用。

但是,这些机制并没有使 Linux 内核成为实时的。用户空间进程仍然必须避免系统调用,因为它们可能会在内核中阻塞。此外,似乎 RTLinux 和 RTAI 都没有得到增强以与可抢占内核一起工作。由于这两种方法都有好处,并且在很大程度上是正交的,因此它们可能会在不久的将来结合起来。这可能是可能的,因为 Love 补丁现在是标准 2.5 内核树的一部分,并且可能在 2.6 内核发布时成为其一部分。

关于选择的一些想法

对于需要实时增强功能的开发人员来说,在 RTLinux、RTAI、Love 可抢占内核和 TimeSys 可抢占内核之间进行选择,存在无数问题。让我们重点介绍一些许多开发人员重视的问题。

  • 哪些是以开源方式维护的,独立的外部人士也做出了贡献?RTAI 和 Love。

  • 哪些对其底层技术拥有软件专利?RTLinux。

  • 哪些是 2.5 Linux 内核树的一部分?Love。

  • 除了可抢占性之外,哪些还具有额外的实时功能?TimeSys、RTAI 和 RTLinux。

  • 哪些定位能够让人合理地假设该解决方案将继续免费提供下载?RTAI 和 Love(恕我直言)。

  • 哪些可以控制中断,并且可能提供接近机器级别的分辨率响应?RTLinux 和 RTAI。

不同处理器的内核可用性

这些实时方法都不能用于 Linux 运行的每个 CPU;需要额外的努力才能使解决方案适应新的处理器。但是,由于我们在此处检查的四种解决方案都有非常积极的开发,因此可以安全地假设至少正在考虑对其他 CPU 的支持。

作为快照,Love 可抢占内核目前仅适用于 x86,但借助 MontaVista 的支持,它很可能会移植到 MontaVista 支持的大部分(如果不是全部)CPU。这包括 PowerPC、ARM、MIPS、SuperH 等。TimeSys 内核目前适用于 PowerPC、ARM、SuperH 和 Pentium。RTLinux 适用于 x86 和 PowerPC。RTAI 适用于 x86 和 PowerPC。

基准测试

您可以从 Web 下载基准测试程序(请参阅 K Computing 基准测试下的“资源”侧边栏)。我们所有的基准测试都是在 465MHz Celeron 上运行的。但是,其他 x86 CPU 也产生了类似的结果。我们尚未在其他类型的 CPU 上进行基准测试。

我们对基于 Linux 内核 2.4.7 的 Red Hat 7.2 内核、基于 Linux 2.4.7 的 TimeSys Linux 3.0 内核以及使用 Robert Love 和 MontaVista 的 Linux 内核 2.4.18 抢占补丁修补的内核进行了基准测试。我们将这些内核分别称为 Red Hat、TimeSys 和 Love。我们分别对 RTAI 和 RTLinux 内核进行了基准测试。

基准测试包括定时调用 nanosleep() 的精度。精确地休眠一段时间与内核可靠地为用户空间实时进程提供服务的能力密切相关。Linux nanosleep() 函数允许人们以纳秒为单位请求休眠。我们的基准测试请求休眠 50 毫秒。有趣的是,请求 nanosleep() 休眠 N 毫秒通常会休眠 10 + N 毫秒。因此,我们测量相对于休眠时间与 60 毫秒的接近程度的抖动。此外,应该注意的是,当休眠请求的时间为两毫秒或更短时,nanosleep() 在内核中是一个忙等待。因此,忙等待不如真正的休眠那样能够很好地模拟中断响应时间。

基准测试程序采集 1,000 个样本。最后 998 个用于图表。前两个被丢弃,以避免因冷缓存而导致的缓存减速。基准测试程序通过 mlockall() 锁定到内存中,并通过 sched_set_scheduler() 和 sched_get_priority_max() 获得最高的 FIFO 优先级。

我们基准测试的核心是

t1 = get_cycles();
nanosleep(fifty_ms, NULL);
t2 = get_cycles();
jitter[i] = t2 - t1;

get_cycles() 函数是一种与机器无关的方式来读取 CPU 的周期计数器。在 x86 机器上,它读取时间戳计数器 (TSC)。TSC 以 CPU 的速率递增。因此,在 500MHz 的 CPU 上,TSC 每秒递增 500,000,000 次。CPU 的频率是通过检查 /proc/cpuinfo 中列出的 CPU 速度值来确定的。TSC 的读取大约需要十个指令时间,并且与我们正在计时的间隔相比非常精确。

对于给定的抖动值,与我们预期的 50 + 10 毫秒休眠时间的毫秒差值计算为

diff = (jitter/KHz) - 10 - 50;

五个基准测试使用了 Benno Senoner 的压力测试,这些测试是他延迟测试基准测试的一部分。这些测试通过复制磁盘文件、读取磁盘文件、写入磁盘文件、读取 /proc 文件系统和执行 X11perf 测试来对系统施加压力。图 2-6 显示了这三个内核在这些负载下的图表。

Real Time and Linux, Part 3: Sub-Kernels and Benchmarks

图 2. 复制磁盘文件

Real Time and Linux, Part 3: Sub-Kernels and Benchmarks

图 3. 读取磁盘文件

Real Time and Linux, Part 3: Sub-Kernels and Benchmarks

图 4. 写入磁盘文件

Real Time and Linux, Part 3: Sub-Kernels and Benchmarks

图 5. 读取 /proc 文件系统

Real Time and Linux, Part 3: Sub-Kernels and Benchmarks

图 6. 执行 X11perf 测试

 

由于 Red Hat 内核的响应速度明显低于 Love 或 TimeSys 内核,因此我们单独绘制了 Love 和 TimeSys 内核结果的图表。这些在图 7-11 中描述。

Real Time and Linux, Part 3: Sub-Kernels and Benchmarks

图 7. Love 和 TimeSys 内核:复制磁盘文件

Real Time and Linux, Part 3: Sub-Kernels and Benchmarks

图 8. Love 和 TimeSys 内核:读取磁盘文件

Real Time and Linux, Part 3: Sub-Kernels and Benchmarks

图 9. Love 和 TimeSys 内核:写入磁盘文件

Real Time and Linux, Part 3: Sub-Kernels and Benchmarks

图 10. Love 和 TimeSys 内核:读取 /proc 文件系统

Real Time and Linux, Part 3: Sub-Kernels and Benchmarks

图 11. Love 和 TimeSys 内核:执行 X11perf 测试

从图表中可以明显看出,可抢占内核在响应速度方面提供了显着改进。由于它们代表了性能的显着提高,而无需更改应用程序需要使用的 API,因此它们显然是嵌入式 Linux 开发人员的有吸引力的选择。

RTLinux 和 RTAI 基准测试

人们有理由期望 RTAI 和 RTLinux 即使在负载很大的情况下也能提供坚如磐石的性能。我们的基准测试证明了它们符合这些期望。但是,必须记住,仍然有一些注意事项。需要记住的一些可能会阻碍实时性能的问题:不要执行任何阻塞操作,例如内存分配;不要使用任何尚未修补以避免真正禁用中断的驱动程序,并避免代价高昂的优先级反转。

为了对 RTAI 和 RTLinux 进行基准测试,我们创建了一个周期性任务,并根据请求的周期性速率测量了其定时性能。RTLinux 和 RTAI 的最坏情况性能约为 30 微秒或更短。我们的基准测试程序可免费下载(请参阅 K Computing 基准测试下的“资源”侧边栏)。

资源

 

Real Time and Linux, Part 3: Sub-Kernels and Benchmarks

 

Kevin Dankwardt 是 K Computing 的创始人兼首席执行官,K Computing 是一家位于硅谷的培训和咨询公司。特别是,他的组织开发并在全球范围内提供嵌入式和实时 Linux 培训。

电子邮件:k@kcomputing.com

加载 Disqus 评论