我正在Linux的串口上实现一个协议。该协议基于请求应答方案,因此吞吐量受到将数据包发送到设备并获得应答所需时间的限制。这些设备大多是基于arm的,运行Linux >= 3.0。我很难将往返时间减少到10ms以下(115200波特,8个数据位,无奇偶校验,每条消息7字节)。
哪些IO接口的延迟最低: select、poll、epoll或使用ioctl手动轮询?阻塞或非阻塞IO是否会影响延迟?
我尝试使用setserial设置low_latency标志。但它似乎没有任何效果。
还有没有其他我可以尝试减少延迟的东西?因为我控制着所有的设备,所以甚至可以给内核打补丁,但它不喜欢这样做。
-编辑
串行控制器使用的是16550A。
发布于 2012-11-15 18:31:39
在与更多的工程师讨论了这个主题后,我得出的结论是,这个问题在用户空间中是无法解决的。由于我们需要跨过桥进入内核领域,我们计划实现一个内核模块,它与我们的协议通信,并给我们提供< 1ms的延迟。
-编辑
事实证明我完全错了。所有需要做的就是增加内核的滴答率。默认的100个滴答添加了10毫秒的延迟。1000 me和负值的串行进程给了我想要达到的时间行为。
发布于 2012-10-30 17:51:27
请求/应答方案往往效率低下,而且在串行端口上很快就会出现。如果您对吞吐量感兴趣,请查看窗口协议,如kermit文件发送协议。
现在,如果您想坚持您的协议并减少延迟,select、poll、read都会提供大致相同的延迟,因为正如Andy Ross所指出的,真正的延迟是在硬件fifo处理中。
如果你幸运的话,你可以在不打补丁的情况下调整驱动程序的行为,但你仍然需要查看驱动程序代码。然而,让ARM处理10 kHz的中断速率肯定不会对整体系统性能有好处……
另一种选择是填充你的数据包,这样你每次都会达到fifo阈值。它还将确认是否存在fifo阈值问题。
10毫秒@ 115200足以传输100字节(假设为8N1),所以您看到的可能是因为没有设置low_latency标志。试一试
setserial /dev/<tty_name> low_latency它将设置low_latency标志,当在tty层中向上移动数据时,内核将使用该标志:
void tty_flip_buffer_push(struct tty_struct *tty)
{
unsigned long flags;
spin_lock_irqsave(&tty->buf.lock, flags);
if (tty->buf.tail != NULL)
tty->buf.tail->commit = tty->buf.tail->used;
spin_unlock_irqrestore(&tty->buf.lock, flags);
if (tty->low_latency)
flush_to_ldisc(&tty->buf.work);
else
schedule_work(&tty->buf.work);
}schedule_work调用可能是您观察到的10毫秒延迟的原因。
发布于 2013-01-23 00:21:19
linux上的串行端口被“包装”到unix风格的终端构造中,这会给您带来1个滴答延迟,即10ms。如果stty -F /dev/ttySx raw low_latency有帮助,请尝试,但不能保证。
在PC上,你可以直接访问标准串口,发出setserial /dev/ttySx uart none命令将linux驱动程序从串口硬件中解绑出来,并通过inb/outb控制端口寄存器。我试过了,效果很好。
缺点是当数据到达时你不会得到中断,你必须轮询寄存器。经常这样。
你应该能够在arm设备端做同样的事情,在外来串行端口hw上可能会困难得多。
https://stackoverflow.com/questions/13126138
复制相似问题