在非实时操作系统/内核上执行接近实时任务的最佳方法是什么?

在GNU / Linux机器上,如果你想做“实时”(亚毫秒级的时间关键)任务,你几乎总是要经历冗长,复杂和容易出问题的修补内核的过程来暴露出足够的支持[ 1] [2] 。

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

所以,我的问题是,为了尽可能接近上述实时目标,最好的第二方式/技巧是什么? 在应用程序源代码中可以简单地做的事情,不需要深入了解底层硬件或太多的“内核黑客行为”。

提升进程优先级,为“关键”任务启动一个额外的线程,以及使用nanosleep()的各种变体(C),这些都是目前为止最好的回答/技巧。 我希望find更多。

Solutions Collecting From Web of "在非实时操作系统/内核上执行接近实时任务的最佳方法是什么?"

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部分了解如何设置任务的时间段。

MRG

亚毫秒在非RT内核上将很难保证。 我知道最近几年发生了很多很好的工作(比如大内核锁),但是还不足以保证。

您可以从CERN和Fermilab那些友好的原子机器人那里看看 Scientific Linux。 这可以安装MRG(请参阅我的链接),它可以为您提供PREEMPT_RT补丁的预包装设置。

或者如果你有钱,你可以得到红帽MRG。 这是一个完全支持的Linux发行版,内置了PREEMPT-RT补丁程序,因此可以避免内核出现问题的情况。

事情是,Redhat会收取很多费用(每年安装3000美元)。 我认为他们已经大跌了,最大的客户之一是高速交易的投资者,他们仍然有很多的交易,所以不会注意到3000美元/箱/年。

我如何与MRG合作

我已经用MRG做了相当多的工作(使用上述两种方法),而且非常好。 它用线程替换了股票内核中的中断服务例程来服务中断。 这意味着你可以在比IRQ线程更高的优先级上运行你的软件! 如果你想接近保证你的应用程序的亚毫秒级的延迟,那你就必须这样做。

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

其他问题

现代CPU热管理可能是一个真正的痛苦的脖子。 我的系统在系统管理中断被系统管理中断服务的时候锁定了0.3秒(而不是操作系统),只是因为CPU温度升高了一点。 看到这个 所以你必须警惕底层硬件的功能。 一般来说,你必须开始担心放弃现代个人电脑的管理散热,并回到一个大风扇的时代。

通过消除其他进程到实时进程的“干扰”,您可以在Linux上获得相当的效果。 我在Windows中玩的是相同的东西,这是一个更大的恐怖得到正确的,但它显示了方向。 所以一种检查列表:

  • 最重要的(奇怪而真实的):硬件。 不要去找笔记本电脑,这将被优化,在SMM中断期间做奇怪的事情。 没有什么可以做的。
  • 驱动程序:Linux(和Windows)有不好的驱动程序和良好的驱动程序。 涉及硬件。 只有一种方法可以找出基准。

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

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

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

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

使其稳定和可重复:

  • 禁用所有节能。 你总是想要同样的表现。
  • 查看所有BIOS设置,并从中删除所有“事件”和“共享”。 所以没有花哨的speedteps,热管理等。选择低延迟,不要选择名称中的“突发”的事情,因为这通常交易吞吐量的性能较差。
  • 查看Linux驱动程序设置,并降低延迟(如果适用)。
  • 使用一个最近的内核,每天试图看起来像一个实时内核多一点。

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

所以:祝你好运:)

最大的问题在于,许多实时任务最有用的系统,即使允许这些补丁工作,也不具备基本的硬件要求,即高分辨率计时器外设。

我强烈不同意:最大的问题是,你可能被阻止或被抢先了一段时间,没有任何警告。 如果你偶尔可以睡500ms,如果你能以1us的精度睡觉,这一点也不重要。 实时计算是保证最差情况下的时间,而不是精确的睡眠时间间隔。 如果你想编程一个I2C EEPROM,你可以从高分辨率的定时器中获益,这个定时器可以让你在不浪费任何时间的情况下尽可能接近设置/保持时间。 偶尔的500ms的随机延迟并不重要,因为EEPROM只是坐在那里等待。 虽然这不是一个实时应用程序。 如果您使用1us更新来实现控制回路来驱动伺服系统,那么在系统运行不受控制的情况下,500毫秒的延迟将导致巨大的位置中断。

在应用程序中,您无法执行任何操作,以解决您的磁盘驱动程序可能花费数百毫秒的时间在中断上下文中处理IO完成的情况。 使RT驱动程序更友好的修补程序是RT内核的原因。