以微秒的级别准确接收RAW套接字数据包

我写了一个代码,每隔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秒到几分钟之间的任何地方断开。

我一直尝试的选项,直到现在。

  1. 设置亲和力到一个特定的孤立核心。
  2. 使用SCHED_FIFO将调度优先级设置为最大
  3. 增加套接字缓冲区大小
  4. networking接口中断关联设置为处理应用程序的相同内核
  5. 使用poll(),select()来旋转recvfrom poll(),select()调用。

所有这些选项都比初始版本的代码有显着的改进。 现在应用程序将运行约1-2小时。 但是这还不够。

几点意见:

  1. 我得到了这些解码时间打印的一个巨大的转储,每当我应用程序运行时(这使得我认为其他1G以太网接口的networking通信正在创build对10G以太网接口的干扰)的Linux机器的SSH会话。
  2. 该应用程序在RHEL(运行时间约2-3小时)中的性能优于Centos(运行时间约为30分钟 – 1.5小时)
  3. 运行时间也随着具有相同操作系统的不同硬件configuration的Linux机器而变化。

请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应用程序与将其移植到硬件的优点/缺点。