什么可能会延迟我的 select() 调用?
What could be delaying my select() call?
我在 Linux 上有一个小程序 运行ning(在嵌入式 PC 上,双核 Intel Atom 1.6GHz 和 Debian 6 运行ning Linux 2.6 .32-5) 通过 FTDI USB 转串口转换器与外部硬件通信(使用 ftdi_sio
内核模块和 /dev/ttyUSB*
设备)。本质上,在我的主循环中我 运行
clock_gettime()
使用 CLOCK_MONOTONIC
select()
超时为 8 毫秒
clock_gettime()
和以前一样
- 输出两次
clock_gettime()
调用的时间差
为了获得一定程度的 "soft" 实时保证,此线程 运行 具有最高优先级 SCHED_FIFO
(在 [=19 中显示为 "RT" =]).它是系统中唯一 运行 具有此优先级的线程,没有其他进程具有这样的优先级。我的进程有另一个 SCHED_FIFO
优先级较低的线程,而其他所有线程都在 SCHED_OTHER
。两个 "real-time" 线程没有 CPU 绑定,除了等待 I/O 和传递数据外几乎没有做任何事情。
我使用的内核没有 RT_PREEMPT 补丁(我以后可能会切换到那个补丁)。我知道如果我想要 "proper" 实时,我需要切换到 RT_PREEMPT 或者,更好的是,Xenomai 或类似的。但尽管如此,我还是想知道 "vanilla" 内核上以下时序异常背后的原因:
- 所有
select()
调用中大约有 0.03% 的时间超过 10 毫秒(请记住,超时为 8 毫秒)。
- 三个最差的情况(超过 1200 万次调用)分别是 31.7 毫秒、46.8 毫秒和 64.4 毫秒。
- 以上所有事件都在 20 秒内发生,我认为可能是某些 cron 作业造成了干扰(尽管除了
cron.daily
正在执行的事实之外,系统日志中的信息很少时间)。
所以,我的问题是:可以在这种极端情况下涉及哪些因素?这只是 Linux 内核本身内部可能发生的事情吗,即我 必须 切换到 RT_PREEMPT,甚至是非 USB 接口和 Xenomai,获得更可靠的保证? /proc/sys/kernel/sched_rt_runtime_us
会咬我吗?还有其他我可能遗漏的因素吗?
提出这个问题的另一种方式是,在不切换到"harder"实时环境的情况下,我还能做些什么来减少这些延迟异常?
更新:我观察到一个新的 "worse worst case" 大约 118.4 毫秒(一次超过总共约 2500 万次 select()
调用)。即使我没有使用带有任何实时扩展的内核,我还是有点担心最后期限显然会错过十分之一秒以上。
没有更多信息,很难指出具体的东西,所以我在这里只是猜测:
- 中断和由中断触发的代码在内核中占用太多时间,以至于您的实时线程明显延迟。这取决于中断的频率,涉及哪些中断处理程序等
- 具有较低优先级的线程不会在内核中被中断,直到它产生 cpu 或离开内核。
- 正如 this SO answer 中所指出的,CPU 系统管理中断和热管理也会导致显着的时间延迟(发帖者观察到长达 300 毫秒)。
118 毫秒对于 1.6GHz CPU 来说似乎很多。但是一个意外锁定 cpu 一段时间的驱动程序就足够了。如果可以,请尝试禁用某些驱动程序或使用不同的 driver/hardware 组合。
如果 sched_rt_period_us
和 sched_rt_period_us
设置为合理的值并且您的代码的行为符合您的预期,则它们应该不是问题。尽管如此,我还是会取消 RT 线程的限制,看看会发生什么。
你还能做什么?写一个设备驱动程序!这并不难,中断处理程序比实时线程获得更高的优先级。切换到实时内核可能更容易,但 YMMV。
我在 Linux 上有一个小程序 运行ning(在嵌入式 PC 上,双核 Intel Atom 1.6GHz 和 Debian 6 运行ning Linux 2.6 .32-5) 通过 FTDI USB 转串口转换器与外部硬件通信(使用 ftdi_sio
内核模块和 /dev/ttyUSB*
设备)。本质上,在我的主循环中我 运行
clock_gettime()
使用CLOCK_MONOTONIC
select()
超时为 8 毫秒clock_gettime()
和以前一样- 输出两次
clock_gettime()
调用的时间差
为了获得一定程度的 "soft" 实时保证,此线程 运行 具有最高优先级 SCHED_FIFO
(在 [=19 中显示为 "RT" =]).它是系统中唯一 运行 具有此优先级的线程,没有其他进程具有这样的优先级。我的进程有另一个 SCHED_FIFO
优先级较低的线程,而其他所有线程都在 SCHED_OTHER
。两个 "real-time" 线程没有 CPU 绑定,除了等待 I/O 和传递数据外几乎没有做任何事情。
我使用的内核没有 RT_PREEMPT 补丁(我以后可能会切换到那个补丁)。我知道如果我想要 "proper" 实时,我需要切换到 RT_PREEMPT 或者,更好的是,Xenomai 或类似的。但尽管如此,我还是想知道 "vanilla" 内核上以下时序异常背后的原因:
- 所有
select()
调用中大约有 0.03% 的时间超过 10 毫秒(请记住,超时为 8 毫秒)。 - 三个最差的情况(超过 1200 万次调用)分别是 31.7 毫秒、46.8 毫秒和 64.4 毫秒。
- 以上所有事件都在 20 秒内发生,我认为可能是某些 cron 作业造成了干扰(尽管除了
cron.daily
正在执行的事实之外,系统日志中的信息很少时间)。
所以,我的问题是:可以在这种极端情况下涉及哪些因素?这只是 Linux 内核本身内部可能发生的事情吗,即我 必须 切换到 RT_PREEMPT,甚至是非 USB 接口和 Xenomai,获得更可靠的保证? /proc/sys/kernel/sched_rt_runtime_us
会咬我吗?还有其他我可能遗漏的因素吗?
提出这个问题的另一种方式是,在不切换到"harder"实时环境的情况下,我还能做些什么来减少这些延迟异常?
更新:我观察到一个新的 "worse worst case" 大约 118.4 毫秒(一次超过总共约 2500 万次 select()
调用)。即使我没有使用带有任何实时扩展的内核,我还是有点担心最后期限显然会错过十分之一秒以上。
没有更多信息,很难指出具体的东西,所以我在这里只是猜测:
- 中断和由中断触发的代码在内核中占用太多时间,以至于您的实时线程明显延迟。这取决于中断的频率,涉及哪些中断处理程序等
- 具有较低优先级的线程不会在内核中被中断,直到它产生 cpu 或离开内核。
- 正如 this SO answer 中所指出的,CPU 系统管理中断和热管理也会导致显着的时间延迟(发帖者观察到长达 300 毫秒)。
118 毫秒对于 1.6GHz CPU 来说似乎很多。但是一个意外锁定 cpu 一段时间的驱动程序就足够了。如果可以,请尝试禁用某些驱动程序或使用不同的 driver/hardware 组合。
如果sched_rt_period_us
和 sched_rt_period_us
设置为合理的值并且您的代码的行为符合您的预期,则它们应该不是问题。尽管如此,我还是会取消 RT 线程的限制,看看会发生什么。
你还能做什么?写一个设备驱动程序!这并不难,中断处理程序比实时线程获得更高的优先级。切换到实时内核可能更容易,但 YMMV。