屏蔽 CPU:标准 Linux 中的实时性能

作者:Steve Brosky

在多处理器系统中,屏蔽 CPU 是专门用于处理高优先级实时任务的 CPU。将 CPU 标记为屏蔽 CPU 可以为高优先级任务保留 CPU 资源。屏蔽 CPU 的执行环境为支持实时应用程序提供了所需的可预测性。换句话说,屏蔽 CPU 使保证对外部中断的快速响应以及为执行实时任务提供更确定的环境成为可能。

过去,屏蔽 CPU 只能在对称多处理系统上创建。随着超线程(单个 CPU 芯片具有多个逻辑 CPU)的出现,即使是单处理器也可以配置为具有屏蔽 CPU。

屏蔽 CPU 提供高端实时性能的方法使实时应用程序的开发者能够获得与使用小型实时执行程序所获得的结果相当的结果。例如,结果可以与 RTAI 或 RT/Linux 等方法相媲美,在这些方法中,Linux 作为实时执行程序下的一个进程运行。与这些执行程序之一相比,使用纯 Linux 环境进行应用程序开发的优势有很多。例如,Linux 支持许多设备驱动程序,从而降低了实现完整应用程序解决方案的总体成本。支持各种高级语言以提高编程效率。这对于商业应用程序很重要;编程效率可能不是实时系统设计的核心,但它在开发阶段很有帮助,并且可以在最终系统中提供额外的功能。此外,Linux 还提供复杂的协议栈(如 CORBA)、广泛的图形功能和高级应用程序开发工具。

除了当今标准 Linux 中提供的所有功能外,由于 Linux 现象的强劲势头,Linux 操作系统还在不断开发越来越多的功能。通过使用 Linux 作为应用程序设计的基础,用户将来将有更多的选择。

实时意味着保证,而不仅仅是速度

实时应用程序是指必须响应现实世界事件并在给定截止日期前完成某些处理任务的应用程序。在截止日期之后交付的正确答案会变成不正确的答案。截止日期本身取决于应用程序,并且可以在几十微秒到几秒之间变化。对于硬实时应用程序,不能错过任何截止日期。这意味着系统指标的最坏情况测量结果是硬实时应用程序唯一重要的事情,因为这些情况会导致错过截止日期。

由于现实世界事件的发生是通过中断传达给计算机系统的,因此实时操作系统必须提供有保证的最坏情况中断响应时间。在响应中断并将控制权交给实时应用程序时,计算机系统已经执行了满足截止日期所需的第一步。一旦实时应用程序正在运行,系统还必须为应用程序提供确定的执行时间。如果与实时应用程序的响应相关的代码的执行时间变化很大,则会错过截止日期。

为了保证良好的中断响应,操作系统必须能够在中断发生时快速抢占任何当前正在执行的任务。由于 2.4 Linux 系列不允许一个任务抢占另一个在内核内部执行的任务的执行,因此基于此系列的内核具有较差的最坏情况中断响应。可以使用抢占补丁使在内核中执行的任务可抢占。然而,即使在安装了抢占补丁的 Linux 内核中,仍然存在一个隐藏的问题,该问题仍然会导致长时间的中断响应延迟。

任何操作系统的任务都是协调共享系统资源的许多任务的执行。如果多个任务同时访问描述这些共享资源的数据结构,则这些数据结构可能会损坏。因此,所有操作系统都具有代码的关键部分,这些代码只能由任务按顺序访问。当高优先级任务突然变得可运行时(因为发生了中断),如果另一个任务当前正在这些关键部分之一内部执行,则该任务无法获得 CPU 的控制权。这意味着长的关键部分对系统响应中断的能力有很大影响。低延迟补丁通过进行缩短关键部分的算法更改来解决 Linux 内核中一些较长的关键部分。

一般来说,子系统越复杂,关键部分就越长。由于 Linux 支持许多如此复杂的子系统,包括文件系统、网络和图形子系统,因此与小型实时操作系统中的关键部分相比,它的关键部分非常长。抢占补丁和低延迟补丁大大提高了 Linux 的响应能力。尽管如此,许多关键部分可以持续数十毫秒——这对于许多实时应用程序所需的截止日期来说是不可接受的。

什么是屏蔽 CPU?

如前所述,屏蔽 CPU 专门用于运行高优先级任务以及与该任务关联的中断。要创建屏蔽 CPU,操作系统必须提供为进程和中断设置 CPU 亲和性的能力。2.4 系列的 Linux 具有为中断设置 CPU 亲和性的能力,并且开放源代码补丁可用于为进程提供此功能。(请参阅“内核角:CPU 亲和性”,《Linux Journal》,2003 年 7 月)。

由于屏蔽 CPU 不运行后台任务,因此屏蔽 CPU 上的高优先级任务永远不会因为另一个任务当前正在该 CPU 上的关键部分内部执行而无法响应中断。中断始终以高于任何任务的优先级执行,并且由于它们在不可预测的时间点发生,因此非实时中断可能会导致进程的预测执行时间出现显着的不确定性。除非中断是屏蔽 CPU 上的高优先级任务正在使用的中断,否则屏蔽 CPU 不允许运行中断。

实现屏蔽 CPU

凭借在进程和中断上设置 CPU 亲和性的能力,可以设置廉价的 CPU 屏蔽实现。但是,此实现将依赖于所有进程都遵守屏蔽 CPU,而不是更改其亲和性以包含屏蔽 CPU。更强大的实现是可取的,下面描述了一种这样的实现。

用于指定 CPU 屏蔽的用户界面是 /proc 接口,管理员可以使用该接口指定屏蔽 CPU 的掩码以及操作此掩码的命令。此接口允许将 CPU 动态标记为屏蔽。一旦 CPU 被屏蔽,除非此禁令阻止进程在任何 CPU 上执行,否则任何进程都不能将其 CPU 亲和性设置为包含屏蔽 CPU。因此,用户必须专门选择屏蔽 CPU 作为其任务应在其上执行的 CPU,以便在屏蔽 CPU 上运行。只有特权进程才能将 CPU 添加到其亲和性掩码。

此实现需要更改设置进程亲和性的代码。例程 sys_sched_setaffinity() 设置 CPU 亲和性。更改此例程以在设置 CPU 亲和性时从任何用户指定的掩码中删除屏蔽 CPU

p->cpus_allowed_user = new_mask;
if (new_mask & ~shielded_proc)
    new_mask &= ~shielded_procs;
set_cpus_allowed(p, new_mask);

请注意,如果删除屏蔽 CPU 位会导致进程没有 CPU 可执行,则不会删除这些位。字段 cpus_allowed_user 是任务结构中的一个新字段,用于保存用户指定的原始进程亲和性。每当屏蔽 CPU 的掩码更改时,上面的代码都需要在系统中的所有进程上重复执行。这需要知道此进程的原始 CPU 亲和性,由用户设置。实现屏蔽 CPU 掩码更改的代码如下所示

for_each_task(p) {
   new_mask = p->cpus_allowed_user & cpu_online_map;
   if (new_mask & ~shielded_proc)
      new_mask &= ~shielded_procs;
   if (new_mask != p->cpus_allowed)
      set_cpus_allowed(p, new_mask);
}

性能测试

为了测量中断响应时间,使用了 Andrew Morton 网站上的 realfeel 基准测试。选择此测试是因为它使用了实时时钟 (RTC) 驱动程序,这是一种用于生成许多 Linux 变体通用的中断的机制。此测试测量对 RTC 驱动程序生成的中断的响应。RTC 驱动程序设置为以 2,048Hz 的速率生成周期性中断。RTC 驱动程序支持 read 系统调用,该调用在下一次中断触发时返回给用户。用于测量中断响应的时钟是 IA-32 TSC 定时器,其分辨率基于 CPU 的时钟速度。为了测量中断响应时间,测试首先读取 TSC 的值,然后循环读取 /dev/rtc。每次读取完成后,测试都会找到 TSC 的当前值。两个连续 TSC 值之间的差值测量进程被阻止等待 RTC 中断的持续时间。预期持续时间为 1/2,048 秒。超出预期持续时间的任何时间都被视为中断响应中的延迟。

为了测量最坏情况中断响应时间,必须在系统上运行繁重的后台工作负载。此工作负载必须为系统提供足够的开销,以导致系统响应中断的能力以及导致不确定性执行的资源争用方面的延迟。选择 Red Hat stress-kernel RPM 作为工作负载。使用了 stress-kernel 中的以下程序:TTCP、FIFOS_MMAP、P3_FPU、FS 和 CRASHME。

TTCP 程序通过环回设备发送和接收大型数据集。FIFOS_MMAP 是一个组合测试,它通过 FIFO 交替在两个进程之间发送数据以及对 mmaped 文件进行操作。P3_FPU 测试通过各种操作处理浮点矩阵。FS 测试对一组文件执行各种操作,例如创建中间有空洞的大文件,然后截断和扩展这些文件。最后,CRASHME 测试生成随机数据缓冲区,然后跳转到该数据并尝试执行它。虽然系统上未生成以太网活动,但系统在测试运行期间仍保持连接到网络并处理标准广播流量。

使用了新版本的 stress-kernel 的 NFS_COMPILE 测试,因为原始版本在其清理中存在错误,阻止了测试长时间运行。NFS_COMPILE 脚本是使用通过环回设备导出的 NFS 文件系统重复编译 Linux 内核。用于运行所有测试的系统是双处理器 Pentium 4 Xeon,具有 1GB 内存和 SCSI 磁盘驱动器。

测试结果

来自 Concurrent Computer Corporation 的 RedHawk Linux 1.3 版用于测量屏蔽 CPU 上的中断响应。RedHawk 是基于 kernel.org 2.4.21 的 Linux 内核。应该注意的是,屏蔽 CPU 只是对 RedHawk Linux 内核进行的实时增强功能之一。其他一些增强功能也为下面报告的性能数据做出了贡献。例如,各种开源补丁已应用于此内核,包括 Robert Love 的抢占补丁、Andrew Morton 的低延迟补丁和 2.5 Linux 树中的 O(1) 调度程序。可能影响此测试性能的其他更改包括减少 Linux 内核中剩余的最坏情况关键部分的算法更改,以及允许在内核守护程序内部执行下半部中断处理的更改,可以指定该守护程序的调度策略和优先级。

图 1 比较了在 RedHawk Linux 下使用屏蔽 CPU 和不使用屏蔽 CPU 测得的中断响应。这些运行之间的差异是惊人的。在这两种测试用例中,大多数情况下系统都能够在 100 微秒内响应 RTC 中断。这表明,总的来说,Linux 能够及时响应中断。然而,如上所述,对于实时系统而言,系统指标最重要的方面是最坏情况下的计时。这是因为最坏情况是可能导致实时应用程序错过截止日期的系统行为示例。

Shielded CPUs: Real-Time Performance in Standard Linux

图 1. 比较屏蔽 CPU 和非屏蔽 CPU 之间的中断响应

在屏蔽 CPU 情况下,RTC 中断的最坏情况中断响应时间为 220 微秒。在未使用 CPU 屏蔽的情况下,所有中断的响应时间都小于 10 毫秒,比屏蔽 CPU 上的最坏情况中断响应时间差一个数量级。虽然在此测试用例中,只有不到百分之一的样本大于 200 微秒,但在数千个案例中,中断响应超过了 500 微秒。在实时系统中,这些案例中的每一个都可能是错过截止日期的机会。

相同的中断响应测试也在未修改的 2.4.21 kernel.org 内核(图 2)以及 Red Hat 8.0(图 3)上运行。此 Red Hat 内核不包含抢占补丁,但它包含低延迟补丁,这些补丁旨在解决 Linux 内核中最长的关键部分。由于这些内核中都不存在屏蔽 CPU,因此结果仅针对非屏蔽情况报告。

Shielded CPUs: Real-Time Performance in Standard Linux

图 2. 中断响应 (kernel.org 2.4.21-pre4)

Shielded CPUs: Real-Time Performance in Standard Linux

图 3. 中断响应 (Red Hat 8.0)

这些内核显示了与在 RedHawk 内核上测得的典型中断响应时间相似的时间,大多数中断发生在 100 微秒以内。然而,这些内核的最坏情况中断响应甚至比 RedHawk Linux 下的非屏蔽情况更差,kernel.org 显示的最坏情况中断响应为 107 毫秒,Red Hat 显示的最坏情况中断响应为 323 毫秒。考虑到这些内核经过调整以在共享系统的进程之间实现公平性以及实现通用系统吞吐量,而不是为了保证实时响应,这些结果并不令人意外。

结论

已经表明,屏蔽 CPU 为 Linux 系统中最坏情况中断响应时间提供了显着改进。屏蔽 CPU 有效是因为它们为系统中最高优先级的任务保留了关键的计算资源。这是在不影响 Linux 的标准应用程序编程接口的情况下完成的。

本文仅讨论了对 RTC 中断的响应;选择它是因为它在大多数 Linux 实现中都是标准功能。然而,通过使用其他中断源和更高度优化的设备驱动程序,可以实现更好的中断响应保证。有关屏蔽 CPU 概念以及设备驱动程序的测试结果的更广泛探索,该设备驱动程序提供了更好的中断响应保证,请参阅白皮书:www.ccur.com/isddocs/wp-shielded-cpu.pdf

Stephen Brosky 是 Concurrent Computer Corporation 集成解决方案部门的首席科学家。他还是 IEEE 委员会的成员,该委员会制定了用于实时应用程序接口和线程接口的 POSIX 1003.1b 和 1003.1c 标准。

加载 Disqus 评论