我正在编写一个代码,它每 1 毫秒从服务器接收一次原始以太网数据包(无 TCP/UDP)。对于收到的每个数据包,我的应用程序必须回复 14 个原始数据包。如果服务器在按计划每 1 毫秒发送一次数据包之前未收到 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
将调度优先级设置为最大 - 增加套接字缓冲区大小
- 将网络接口(interface)中断关联设置为处理应用程序的同一核心
- 使用
poll(),select()
调用旋转recvfrom
。
所有这些选项都比初始版本的代码有了显着改进。现在应用程序将运行约 1-2 小时。但这还不够。
一些观察:
- 每当我在应用程序运行时对 Linux 机器进行 ssh session 时,我都会得到这些解码时间打印的大量转储(这让我认为通过其他 1G 以太网接口(interface)进行的网络通信正在对 10G 以太网接口(interface)产生干扰)。
- 该应用程序在 RHEL(运行时间约 2-3 小时)中的性能优于 Centos(运行时间约 30 分钟 - 1.5 小时)
- 运行时间也因具有不同硬件配置和相同操作系统的 Linux 机器而异。
如果有任何其他方法可以提高应用程序的运行时间,请提出建议。
提前致谢。
最佳答案
首先需要验证时间戳方法的准确性; clock_gettime。分辨率是纳秒级,但是准确度和精密度有问题。这不是您问题的答案,但会在继续之前告知时间戳的可靠性。参见 Difference between CLOCK_REALTIME and CLOCK_MONOTONIC?为什么 CLOCK_MONOTONIC 应该用于您的应用程序。
我怀疑大部分解码时间波动是由于每次解码的操作数量可变、操作系统的上下文切换或 IRQ。
每次解码的操作我无法评论,因为代码已在您的帖子中得到简化。也可以分析和检查此问题。
可以轻松检查和监控每个进程的上下文切换 https://unix.stackexchange.com/a/84345
正如 Ron 所说,这些是对网络的非常严格的时序要求。它必须是一个孤立的网络,并且只有一个目的。当 ssh'ing 表明必须阻止所有其他流量时,您对解码超时的观察。考虑到单独的 NIC,这令人不安。因此我怀疑 IRQ 是问题所在。参见/proc/interrupts。
要在很长的时间间隔(小时 -> 天)内实现一致的解码时间,需要大幅简化操作系统。删除不必要的进程和服务、硬件,并可能构建您自己的内核。一切都是为了减少上下文切换和中断的目标。此时应考虑实时操作系统。这只会提高解码时间一致的概率,并不能保证。
我的工作是开发一个结合了 FPGA ADC、PC 和以太网的数据采集系统。不可避免地,多用途 PC 的不一致性意味着某些功能必须转移到专用硬件上。考虑为 PC 开发应用程序与将其转移到硬件上的优缺点。
关于c - 以微秒级精度接收 RAW 套接字数据包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35357567/