首页 文章

在非实时OS /内核上接近实时任务的最佳方法是什么?

提问于
浏览
9

在GNU / Linux机器上,如果想要执行"real-time"(亚毫秒时间关键)任务,您几乎总是必须经历修补内核的冗长,复杂且容易出错的过程以暴露足够的支持[1] [2] .

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

所以,我的问题是,有哪些最好的第二方式/技巧可以尽可能接近上述实时目标?人们可以简单地在应用程序源代码中做的事情,而不需要深入了解底层硬件或太多"kernel hacking" .

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

4 回答

  • 2

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

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

    使用"real-time"调度程序,最多有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部分 .

  • 3

    MRG

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

    您可以从CERN和Fermilab的那些友好的原子 - 僵尸程序中获取Scientific Linux的look . 可以安装MRG(参见我的链接),它为您提供了PREEMPT_RT补丁的预包装设置 .

    或者,如果你有钱,你可以得到Redhat MRG . 这是一个完全支持的Linux发行版,内置了PREEMPT-RT补丁,因此可以解决内核修补问题 .

    事实上,Redhat为它收取了很多费用(每年安装3000美元) . 我想他们注意到3000美元/盒/年出门了 .

    How I Got On with MRG

    如果你想接近保证应用程序的亚毫秒延迟,那么你需要做的事情 .

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

    Other Gotchas

    现代CPU热管理可能是一个真正的痛苦 . 我've had systems which lock up for 0.3 seconds whilst a System Management Interrupt was being serviced (by the bleedin' BIOS,而不是操作系统),只是因为CPU的预热了一点点 . 见this . 因此,您必须警惕底层硬件的功能 . 一般来说,你必须开始担心放弃现代个人电脑的管理冷却,然后回到一个快速旋转的大风扇 .

  • 4

    通过消除其他进程到实时进程的“干扰”,你可以在Linux上走得很远 . 我在Windows中使用了同样的东西,这是一个更大的恐怖,但它显示了方向 . 所以一种检查清单:

    • 最重要的(奇怪但真实):硬件 . 不要去买笔记本电脑,这将被优化为在SMM中断期间做一些奇怪的事情 . 你什么都做不了 .

    • 驱动程序:Linux(和Windows)有糟糕的驱动程序和良好的驱动程序 . 与硬件有关 . 而且只有一种方法可以找到:基准测试 .

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

    • 隔离一个CPU( man cpuset ) . 创建两个CPU集,一个用于正常流程,一个用于实时流程 .

    • 将代码的实时部分降至最低 . 与系统的其他部分的大缓冲区通信 . 将IO减少到最小值(因为IO有不好的保证) .

    • 使进程具有最高(软)实时优先级 .

    • 禁用超线程(您不想共享)

    • 预分配你需要的内存,并mlock()内存 .

    • 隔离您使用的设备 . 首先为设备分配专用IRQ(将其他设备移动到另一个IRQ,或删除其他设备/驱动程序) .

    • 隔离您使用的IO .

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

    • 只启动你真正需要的进程 .

    • 删除不需要的硬件,如磁盘和其他硬件 .

    • 禁用交换 .

    • 不要使用Linux内核模块或预先加载它们 . 模块的init是不可预测的 .

    • 最好删除用户也:)

    使其稳定和可重复:

    • 禁用所有节能 . 您希望始终保持相同的性能 .

    • 检查所有BIOS设置,并从中删除所有'eventing'和'sharing' . 因此,没有花哨的速度步骤,热管理等 . 选择低延迟,因为它通常将吞吐量换成性能更差 .

    • 检查Linux驱动程序设置,并降低延迟(如果适用) .

    • 使用最近的内核,它每天尝试看起来像一个实时内核 .

    然后进行基准测试,使用压力测试并将机器打开数天,同时记录最大值 . 延迟 .

    所以:祝你好运:)

  • 1

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

    我强烈不同意:最大的问题是你可能会在没有任何警告的情况下被阻止或抢占任意时间 . 如果你可能偶尔睡觉500毫秒,你可以以1us的准确度睡觉并不重要 . 实时计算是关于保证最坏情况的时间,而不是精确的睡眠间隔 . 如果您想对I2C EEPROM进行编程,您可以从高分辨率定时器中受益,该定时器可以让您尽可能地满足 Build /保持时间,而不会浪费任何时间 . 偶尔随机延迟500ms并不重要,因为EEPROM只会坐在那里等待 . 但这不是一个实时应用程序 . 如果您正在实施一个带有1us更新的控制回路来驱动 Servo 系统,那么500ms的延迟将导致系统在系统不受控制地运行时发生巨大的位置中断 .

    您无法在应用程序中执行任何操作来解决磁盘驱动程序在中断上下文中花费数百毫秒处理IO完成的事实 . 使驱动程序对RT应用程序更友好的补丁是构成RT内核的补丁 .

相关问题