我有一个实时过程,通过RS232向高速摄像机发送偶尔的通信。我有几个其他的实时进程占用了大量的CPU时间,使用CUDA在几个GPU板上进行图像处理。通常串行通信非常快,每次消息和响应大约需要50毫秒。然而,当后台进程忙于图像处理时,串行通信变慢,通常需要数秒(有时超过10秒)。
总之,在串行通信期间,如果进程B、C等非常忙,进程A就会延迟,即使进程A具有最高优先级:
- 进程A(实时,最高优先级):偶尔串行通信
- 进程B、C、D等(实时,低优先级):CPU和GPU处理繁重
当我将后台进程更改为SCHED_OTHER(非实时)进程时,串行通信速度很快;然而,这对我来说不是一个解决方案,因为后台进程需要是实时进程(当它们不是时,GPU处理不能充分跟上高速相机)。
显然,串行通信依赖于系统中的一些非实时进程,这些进程被我的实时后台进程抢占了。我想如果我知道哪个进程被用于串行通信,我就可以提高它的优先级并解决问题。有人知道串行通信是否依赖于系统上运行的任何特定进程吗?
我正在运行RHEL 6.5,标准内核(不是PREEMPT_RT)。它有双6核cpu。
在Erki A的建议下,我捕捉到了一个恍惚。显然,这是一个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!rn", 4096) = 5 <0.000092>
缓慢的select()使它看起来像相机本身是缓慢的响应。然而,我知道这不是真的,因为改变后台进程优先级会影响速度。在这种情况下,select()是否依赖于某个正在运行的其他进程?
如果我跳过select()而只执行read(),则read()系统调用是较慢的。
取决于您的串行设备/驱动程序,串行通信最有可能依赖于内核工作线程(kworker)将传入的串行数据从中断服务例程缓冲区转移到行规程缓冲区。您可以提高内核工作线程的优先级,但是,工作线程处理共享工作队列。因此,增加工作线程的优先级将增加串行处理的优先级,以及一大堆可能不需要优先级提升的其他东西。
您可以修改串行驱动程序以使用专用的高优先级工作队列而不是共享的。另一种选择是使用微线程,然而,这两种方法都需要在驱动程序级别进行修改。
我怀疑最直接的解决方案是将com端口设置为低延迟模式,或者从命令行通过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秒,应该很容易看到