我有一个实时进程偶尔通过RS232传输到高速摄像机。 我还有几个其他的实时进程占用了大量的CPU时间,使用CUDA在几个GPU板上进行image processing。 通常串行通信速度非常快,每次消息和响应时间约为50毫秒。 但是,当后台进程忙于进行image processing时,串行通信速度减慢,往往需要几秒钟(有时超过10秒)。
总之,在串行通信期间,即使进程A具有最高的优先级,如果进程B,C等非常繁忙,进程A也会延迟:
当我将后台进程改为SCHED_OTHER(非实时)进程时,串口通讯速度很快; 然而,这对我来说不是一个解决scheme,因为后台进程需要是实时进程(如果不是这样的话,GPU处理没有跟上高速摄像机的步伐)。
显然,串行通信是依赖于系统中的一些非实时进程,而这些正在被我的实时后台进程所抢占。 我想如果我知道哪个进程用于串行通信,我可以增加优先级并解决问题。 有谁知道串行通信是否依赖于系统上运行的任何特定进程?
我使用标准内核(不是PREEMPT_RT)运行RHEL 6.5。 它具有双核6核CPU。
Erki A的build议,我抓住了一个strace。 显然这是一个select()系统调用,它是慢的(“set roi2”是相机的命令,最后的“OK!”是来自相机的响应):
write(9, "set roi2"..., 26) = 26 <0.001106> ioctl(9, TCSBRK, 0x1) = 0 <0.000263> select(10, [9], NULL, NULL, {2, 0}) = 1 (in [9], left {0, 0}) <2.252840> read(9, "Ok!\r\n", 4096) = 5 <0.000092>
慢select()使得它看起来像相机本身响应缓慢。 但是,我知道这是不正确的,因为速度受到改变后台进程优先级的影响。 select()在这种情况下依赖于某个其他进程在运行吗?
如果我跳过了select()并且只是执行read(),read()系统调用就是缓慢的。
根据串行设备/驱动程序的不同,串行通信很可能依靠内核工作线程(kworker)将输入的串行数据从中断服务程序缓冲区移到线程缓冲区。 您可以增加内核工作线程的优先级,但是,工作线程会处理共享的工作队列。 因此,增加工作线程的优先级将会增加串行处理的优先级以及其他一些可能不需要优先级提升的东西。
您可以修改串行驱动程序以使用专用的高优先级工作队列,而不是共享的。 另一个选择是使用一个tasklet,但是,这两个都需要驱动程序级别的修改。
我怀疑最简单的解决方案是通过setserial命令将命令行设置为低延迟模式:
setserial / dev / ttySxx low_latency
或编程:
struct serial_struct serinfo; fd = open ("/dev/ttySxx"); ioctl (fd, TIOCGSERIAL, &serinfo); serinfo.flags |= ASYNC_LOW_LATENCY; ioctl (fd, TIOCSSERIAL, &serinfo); close (fd);
这将导致串行端口中断处理程序立即将传入数据传输到线路规程,而不是通过将传输数据添加到工作队列来推迟传输。 在这种模式下,当你从你的应用程序中调用read()的时候,如果在工作队列中有工作要刷新的话,你将避免read()调用的休眠的可能性。 这种睡眠可能是间歇性延迟的原因。
您可以使用strace
来查看它锁定的位置。 如果超过10秒,应该很容易看到。