我写了一个代码,每隔1ms从服务器接收原始以太网数据包(无TCP / UDP)。 对于每个收到的数据包,我的应用程序必须回复14个原始数据包。 如果服务器在每隔1ms发送数据包之前没有收到14个数据包,服务器就会发出警报,应用程序不得不中断。 服务器 – 客户端通信是一对一的链接。
服务器是一个硬件(FPGA),它以精确的1ms间隔生成数据包。 客户端应用程序在具有10G SolarFlare NIC的Linux(RHEL / Centos 7)机器上运行。
我的第一个版本的代码是这样的
while(1) { while(1) { numbytes = recvfrom(sockfd, buf, sizeof(buf), 0, NULL, NULL); if(numbytes > 0) { //Some more lines here, to read packet number break; } } for (i=0;i<14;i++) { if (sendto(sockfd,(void *)(sym) , sizeof(sym), 0, NULL, NULL) < 0) perror("Send failed\n"); } }
我通过在recvfrom
调用之前获取时间戳(使用clock_gettime
)来测量接收时间,然后在打印时间戳之后打印这些时间戳的时间差,并在时间差超过900-1100 us的允许范围时打印它们。
我面临的问题是数据包的接收时间是波动的。像这样的东西(打印以微秒为单位)
Decode Time : 1234 Decode Time : 762 Decode Time : 1593 Decode Time : 406 Decode Time : 1703 Decode Time : 257 Decode Time : 1493 Decode Time : 514 and so on..
有时解码时间超过2000us,应用程序将中断。
在这种情况下,应用程序将在2秒到几分钟之间的任何地方断开。
我一直尝试的选项,直到现在。
SCHED_FIFO
将调度优先级设置为最大 poll(),select()
来旋转recvfrom
poll(),select()
调用。 所有这些选项都比初始版本的代码有显着的改进。 现在应用程序将运行约1-2小时。 但是这还不够。
几点意见:
请build议是否有其他方法来提高应用程序的运行时间。
提前致谢。
首先,您需要验证时间戳方法的准确性; clock_gettime。 分辨率是纳秒,但准确度和精确度是有问题的。 这不是你的问题的答案,但通知在进行之前时间戳的可靠性。 请参阅CLOCK_REALTIME和CLOCK_MONOTONIC之间的区别? 为什么CLOCK_MONOTONIC应该用于你的应用程序。
我怀疑大部分的解码时间波动是由于每个解码操作数量不定,操作系统的上下文切换或IRQ。
每个解码操作我不能评论,因为代码已经简化了您的文章。 这个问题也可以分析和检查。
上下文切换每个进程可以很容易地检查和监控https://unix.stackexchange.com/a/84345
正如罗恩所说的那样,这对网络来说是非常严格的时间要求。 它必须是一个孤立的网络,一个目的。 你对ssh'ing的解码时间的观察表明所有其他流量必须被阻止。 这是令人不安的,给单独的网卡。 因此我怀疑IRQ是个问题。 请参阅/ proc / interrupts。
要在长时间间隔(小时 – >天)内实现一致的解码时间,将需要极大地简化操作系统。 删除不必要的进程和服务,硬件,也许建立你自己的内核。 所有的目标都是为了减少上下文切换和中断。 此时应考虑实时操作系统。 这只会提高一致解码时间的概率,不能保证。
我的工作是开发一个数据采集系统,它是FPGA ADC,PC和以太网的组合。 不可避免地,多用途PC的不一致意味着必须将某些功能转移到专用硬件。 考虑开发您的PC应用程序与将其移植到硬件的优点/缺点。