9

在 GNU/Linux 机器上,如果想要执行“实时”(亚毫秒级时间关键)任务,您几乎总是必须经历冗长、复杂且容易出现问题的内核修补过程以提供足够的支持[ 1] [2]

最大的问题是,许多实时任务最有用的系统甚至没有基本的硬件要求来允许这些补丁工作,即高分辨率定时器外围设备。或者如果他们这样做,它是特定于硬件的,因此需要根据具体情况在补丁中具体实施。即使 CPU/指令时钟速率足够快,可以提供所需的时间粒度,甚至更多,也是如此。

所以,我的问题是,有哪些最好的方法/技巧可以尽可能接近上述实时目标?可以简单地在应用程序源代码中完成的事情,无需深入了解底层硬件或过多的“内核黑客”。

提升进程优先级,为“关键”任务启动一个额外的线程,以及(在 C 中)使用 nanosleep() 的变体是迄今为止我想出的最好看的答案/技巧。我希望能找到更多。

4

4 回答 4

4

sched_setscheduler (2)和朋友允许您使用两种不同的软实时调度器,SCHED_FIFO SCHED_RR。在这些调度程序下运行的进程的优先级高于常规进程。所以只要你只有几个这些进程,并控制它们之间的优先级,你实际上可以获得相当下降的实时响应。

根据评论中的要求,这是 SCHED_FIFO 和 SCHED_RR 之间的区别:

使用“实时”调度程序,最多有 100 个不同的优先级(POSIX 只需要 32 个不同的级别,因此应该使用sched_get_priority_min(2)sched_get_priority_max(2)来获取实际数量。调度程序都通过抢占进程工作和具有较低优先级的线程,区别在于它们如何处理具有相同优先级的任务。

SCHED_FIFO,是一个先进先出的调度器(因此得名)。这意味着首先到达运行队列的任务,被允许运行直到它完成,自愿放弃它在运行队列上的空间,或者被更高优先级的任务抢占。

SCHED_RR,是一个循环调度器。这意味着具有相同优先级的任务只允许运行一定的时间段。如果在这个时间段用完时任务仍在运行,则任务被抢占,并允许运行队列中的下一个任务(具有相同优先级)运行直到其时间段。与 SCHED_FIFO 一样,较高优先级的任务会抢占较低优先级的任务,但是,当允许被较高优先级任务抢占的任务再次运行时,它只允许运行其时间片中剩余的时间。请参阅sched_rr_get_interval(2)中的 Noes 部分,了解如何设置任务的时间段。

于 2013-03-21T15:34:28.143 回答
4

MRG

在非 RT 内核上很难保证亚毫秒级。我知道近年来发生了很多非常好的工作(例如大内核锁已经消失),但这仍然不足以保证它。

您可以从 CERN 和 Fermilab 的友好原子困扰者那里了解Scientific Linux。这可以安装 MRG(请参阅我的链接),它为您提供 PREEMPT_RT 补丁的预打包设置。

或者,如果您有钱,您可以购买 Redhat MRG。这是一个完全支持的 Linux 发行版,内置了 PREEMPT-RT 补丁,因此可以消除容易出现问题的内核补丁。

问题是,Redhat 收取了很多费用(每次安装每年 3000 美元)。我认为他们已经跌倒了,它的最大客户之一是高速交易投资者,他们仍然有很多美元,因此不会注意到每盒每年 3000 美元的价格。

我是如何与 MRG 相处的

我已经用 MRG 做了很多工作(使用上述两种方法),它非常好。它用服务中断的线程替换了普通内核中的中断服务例程。这意味着您可以以高于 IRQ 线程的优先级运行您的软件!如果您想接近保证应用程序的亚毫秒延迟,这就是您必须做的事情。

似乎 MRG 的东西逐渐漂移到主线内核中,在我看来这是一件好事。也许有一天它会成为主线的东西。

其他陷阱

现代 CPU 热管理可能是一个真正的痛苦。我的系统在处理系统管理中断时锁定了 0.3 秒(通过 bleedin' BIOS,而不是操作系统),只是因为 CPU 有点热身。看到这个。因此,您必须警惕底层硬件的功能。通常,您必须开始担心放弃现代 PC 的管理冷却,并回到一直快速旋转的大风扇。

于 2013-03-21T22:35:40.673 回答
2

通过消除从其他进程到实时进程的“干扰”,您可以在 Linux 上走得更远。我在 Windows 中玩过同样的东西,这是一个更大的恐惧,但它显示了方向。所以一种清单:

  • 最重要(奇怪但真实):硬件。不要选择笔记本电脑,这将被优化为在 SMM 中断期间做奇怪的事情。你无能为力。
  • 驱动程序:Linux(和 Windows)有坏的驱动程序和好的驱动程序。与硬件有关。只有一种方法可以找出答案:基准测试。

与系统的其余部分隔离,禁用所有共享:

  • 隔离一个 CPU ( man cpuset)。创建两个 CPU 集,一个用于正常进程,一个用于实时进程。
  • 将代码的实时部分减少到最低限度。与系统其他部分的大缓冲区通信。将 IO 减少到最低限度(因为 IO 有不好的保证)。
  • 使进程具有最高(软)实时优先级。
  • 禁用超线程(您不想共享)
  • 预先分配你需要的内存,然后 mlock() 内存。
  • 隔离您使用的设备。首先为设备分配一个专用的 IRQ(将其他设备移动到另一个 IRQ,或删除其他设备/驱动程序)。
  • 隔离您使用的 IO。

减少系统其余部分的活动:

  • 只启动您真正需要的流程。
  • 删除不需要的硬件,例如磁盘和其他硬件。
  • 禁用交换。
  • 不要使用 Linux 内核模块或预先加载它们。模块的初始化是不可预测的。
  • 最好也删除用户:)

使其稳定且可重现:

  • 禁用所有节能。您始终想要相同的性能。
  • 查看所有 BIOS 设置,并从中删除所有“事件”和“共享”。所以没有花哨的速度步骤,热管理等。选择低延迟,不要选择名称中带有“突发”的东西,因为这通常会以吞吐量换取更差的性能。
  • 查看 Linux 驱动程序设置和更低的延迟(如果适用)。
  • 使用最近的内核,它每天都试图看起来像一个实时内核。

然后进行基准测试,使用压力测试并在记录最大值的同时让机器开启数天。延迟。

所以:祝你好运:)

于 2013-03-21T23:01:04.933 回答
1

最大的问题是,许多实时任务最有用的系统甚至没有基本的硬件要求来允许这些补丁工作,即高分辨率定时器外围设备。

我非常不同意:最大的问题是您可能会在没有任何警告的情况下被封锁或抢占任意时间。如果您偶尔会睡 500 毫秒,那么您能否以 1 微秒的精度入睡并不重要。实时计算是关于保证最坏情况的时间,而不是精确的睡眠间隔。如果您想对 I2C EEPROM 进行编程,您可以从高分辨率定时器中受益,它可以让您尽可能接近设置/保持时间,而不会浪费任何时间。偶尔的 500 毫秒随机延迟无关紧要,因为 EEPROM 只会坐在那里等待。不过,这不是一个实时应用程序。如果您正在实施一个具有 1us 更新的控制回路来驱动伺服器,那么 500ms 的延迟将在系统不受控制地运行时导致巨大的位置中断。

您无法在应用程序中做任何事情来解决您的磁盘驱动程序可能会花费数百毫秒处理中断上下文中的 IO 完成的事实。使驱动程序对 RT 应用程序更友好的补丁是构成 RT 内核的原因。

于 2013-03-21T23:38:44.300 回答