实时内核补丁集

出自 ArchWiki

此文章或章节是移动到 实时内核 的候选对象。

注意: PREEMPT_RT 已合并到 Linux 6.12 中。(在 Talk:Realtime kernel patchset 中讨论)

本文介绍了 Linux 内核 实时补丁集,以及一些有助于解决调度延迟问题的实用工具。

注意: 实时内核支持已合并到 Linux 6.12 中。

什么是实时性?

实时 应用程序在某些触发事件和应用程序对该事件的响应之间具有操作截止时间。为了满足这些操作截止时间,程序员使用实时操作系统 (RTOS),在实时操作系统上,对于给定的应用程序和环境,最大响应时间可以可靠地计算或测量。典型的 RTOS 使用优先级。想要 CPU 的最高优先级任务总是在唤醒任务的事件发生后的固定时间内获得 CPU。在这样的 RTOS 上,任务的延迟仅取决于以相同或更高优先级运行的任务;可以忽略以较低优先级运行的任务。在非实时操作系统(大多数运行默认内核的 GNU/Linux 发行版)上,由于延迟取决于系统上运行的每个进程,因此显然更难以确保每次都能满足截止时间,并且这种困难随系统复杂性呈非线性增长。调度中的确定性变得更加难以实现,因为可以关闭抢占任意时间。因此,想要运行的高优先级任务可能会被禁用抢占的低优先级任务无限期地延迟。

实时补丁如何工作

RT-Preempt 补丁将 Linux 转换为完全可抢占内核。这通过以下方式完成

  • 通过使用 rtmutexes 重新实现,使内核锁定原语(使用自旋锁)可抢占。
  • 由 i.e. spinlock_t 和 rwlock_t 保护的临界区现在是可抢占的。仍然可以使用 raw_spinlock_t(与 spinlock_t 相同的 API)创建不可抢占的区段(在内核中)。
  • 为内核自旋锁和信号量实现优先级继承
  • 将中断处理程序转换为可抢占内核线程:RT-Preempt 补丁在内核线程上下文中处理软中断处理程序,内核线程上下文由 task_struct 表示,就像常见的用户空间进程一样。但是,也可以在内核上下文中注册 IRQ。
  • 将旧的 Linux 定时器 API 转换为单独的基础架构,用于高分辨率内核定时器以及超时,从而产生具有高分辨率的用户空间 POSIX 定时器。

安装

有两个可用的实时补丁内核:linux-rtlinux-rt-lts,它们都具有基于主 linux 内核软件包的配置。 linux-rt 遵循 -rt 补丁的开发分支,而 linux-rt-lts 跟踪 rt 补丁集的稳定分支。

注意: 不要忘记将新安装的内核添加到您的引导加载程序

调度延迟

在调度器的上下文中,延迟是从事件发生到处理所述事件所经过的时间。通常是从中断触发到中断处理程序开始运行的延迟,但也可能是从定时器到期等的延迟。

高调度延迟可能有很多不同的原因。一些值得一提的原因(没有特定的顺序)是:配置错误的系统、不良硬件、错误编程的内核模块、CPU 电源管理、错误的硬件定时器、SMISMT

当尝试确定系统的最大调度延迟时,需要使系统处于负载之下。繁忙的系统往往比空闲系统经历更大的延迟。为了充分表征感兴趣的延迟,谨慎的做法是长时间并在各种标称和最坏情况负载条件下运行测试。此外,由于诸如磁盘、网络设备、USB 和图形等许多子系统在系统上线后可能会稀疏地使用,因此应注意在这些子系统也处于活动状态时表征延迟。

延迟测试工具

理解延迟是非直观的。在测量和解释延迟时,即使是经验丰富的计算机科学家也经常会犯错误并且极有可能发生错误。流行的工具通常是不正确的。 这个演讲解释了一些常见的陷阱。有几种工具可用于检查内核调度延迟,并追踪延迟峰值的原因。一组工具包含在一个名为 rt-tests 的软件包中。

cyclictest

rt-tests 中的程序之一称为 cyclictest,它可用于验证最大调度延迟,并用于追踪延迟峰值的原因。 cyclictest 的工作原理是测量线程设置的定时器到期的时间与线程再次开始运行的时间之间的时间。

以下是典型测试运行的结果

# cyclictest --smp -p98 -m
# /dev/cpu_dma_latency set to 0us
policy: fifo: loadavg: 239.09 220.49 134.53 142/1304 23799          

T: 0 (23124) P:98 I:1000 C: 645663 Min:      2 Act:    4 Avg:    4 Max:      23
T: 1 (23125) P:98 I:1500 C: 430429 Min:      2 Act:    5 Avg:    3 Max:      23
T: 2 (23126) P:98 I:2000 C: 322819 Min:      2 Act:    4 Avg:    3 Max:      15
T: 3 (23127) P:98 I:2500 C: 258247 Min:      2 Act:    5 Avg:    4 Max:      32
^C

它显示了一个四核 CPU 系统,每个核心运行一个线程 (SCHED_FIFO),优先级为 98,内存已锁定,并且由于在单独的终端中运行 hackbench,系统也处于高负载状态。最有趣的是检测到的最大调度延迟,在本例中,核心 3 上为 32 微秒。

请参阅 cyclictest(8) 手册页。

hackbench

空闲内核往往会显示低得多的调度延迟,必须对其施加一些负载才能获得真实的结果。这可以使用 rt-tests 软件包中的另一个实用程序 hackbench 来完成。它的工作原理是创建多对线程或进程,这些线程或进程通过套接字或管道在彼此之间传递数据。要使其运行更长时间,请添加 -l 参数:hackbench -l 1000000

请参阅 hackbench(8) 手册页。

hwlatdetect

hwlatdetect 可用于检测占用过长时间的 SMI,从而通过阻止正常的内核执行来引入延迟。它由一个内核模块(linux-rt 和 linux-rt-lts 中都存在)和一个 python 脚本组成,用于启动进程并将结果报告给用户。要检查系统是否使用 NMI,请运行以下命令

$ grep NMI /proc/interrupts
 
NMI:       3335       3336       3335       3335   Non-maskable interrupts

hwlatdetect 内核模块的工作原理是通过 stop_machine() 调用关闭 CPU 上运行的所有内容。然后,它轮询 TSC(时间戳计数器)以查找生成的数据流中的间隙。任何间隙都表明它被 NMI 中断,因为它们是唯一可能的机制(除了损坏的 TSC 实现)。要运行该程序 120 秒,检测阈值为 15 微秒,请执行以下操作

# hwlatdetect --duration=120 --threshold=15
hwlatdetect:  test duration 120 seconds
   parameters:
        Latency threshold: 15us
        Sample window:     1000000us
        Sample width:      500000us
     Non-sampling period:  500000us
        Output File:       None

Starting test
test finished
Max Latency: 21us
Samples recorded: 16
Samples exceeding threshold: 16
1408928107.0286324723   18      17
.
.
1408928180.0296881126   15      21
.
.
1408928212.0300332889   18      18

结果显示检测到 16 个 NMI 超出指定的 15 微秒阈值,检测到的最大延迟为 21 微秒。

请参阅 hwlatdetect(8) 手册页。

参见