2012-08-08 261 views
8

我有一个以819.2Hz(〜1.2ms)的速率向我的QNX Neutrino机器发送UDP数据包的源。我想以尽可能小的延迟和抖动来接收和处理这些消息。使用QNX RTOS实时接收UDP数据包

我的第一代码基本上是:

SetupUDPSocket(); 
while (true) { 
    recv(socket, buffer, BufferSize, MSG_WAITALL); // blocks until whole packet is received 
    processPacket(buffer); 
} 

的问题是,的recv()仅在系统的每个计时器滴答检查是否有可用的新的分组。计时器刻度通常为1ms。所以,如果我使用这个,我会得到一个巨大的抖动,因为我每隔1ms或每2ms处理一个数据包。我可以重置计时器滴答的大小,但这会影响整个系统(以及其他进程的其他定时器等)。而且我仍然会有抖动,因为我绝对不会完全匹配819.2赫兹。

所以,我试图使用网卡(5)的中断线。但是,似乎也有其他的事情导致中断上升。我以前的代码如下:

ThreadCtl(_NTO_TCTL_IO, 0); 
SIGEV_INTR_INIT(&event); 
iID = InterruptAttachEvent(IRQ5, &event, _NTO_INTR_FLAGS_TRK_MSK); 

while(true) { 
    if (InterruptWait(0, NULL) == -1) { 
     std::cerr << "errno: " << errno << std::endl; 
    } 

    length = recv(socket, buffer, bufferSize, 0); // non-blocking this time 

    LogTimeAndLength(); 

    InterruptUnmask(IRQ5, iID; 
} 

这会导致一次成功的读取,然后在0时间过后读取0字节长度的数据。看起来,在执行完InterruptUnmask()后,InterruptWait()根本不会等待,所以必须有一个新的中断(或相同的?!)。

是否有可能做这样的事情与网卡的中断线?是否有其他可能性以819.2 Hz的速率接收数据包?

关于网卡的一些信息: 'PCI -vvv' 输出:

Class   = Network (Ethernet) 
Vendor ID  = 8086h, Intel Corporation 
Device ID  = 107ch, 82541PI Gigabit Ethernet Controller 
PCI index  = 0h 
Class Codes = 020000h 
Revision ID = 5h 
Bus number  = 4 
Device number = 15 
Function num = 0 
Status Reg  = 230h 
Command Reg = 17h 
I/O space access enabled 
Memory space access enabled 
Bus Master enabled 
Special Cycle operations ignored 
Memory Write and Invalidate enabled 
Palette Snooping disabled 
Parity Error Response disabled 
Data/Address stepping disabled 
SERR# driver disabled 
Fast back-to-back transactions to different agents disabled 
Header type = 0h Single-function 
BIST   = 0h Build-in-self-test not supported 
Latency Timer = 40h 
Cache Line Size= 8h un-cacheable 
PCI Mem Address = febc0000h 32bit length 131072 enabled 
PCI Mem Address = feba0000h 32bit length 131072 enabled 
PCI IO Address = ec00h length 64 enabled 
Subsystem Vendor ID = 8086h 
Subsystem ID  = 1376h 
PCI Expansion ROM = feb80000h length 131072 disabled 
Max Lat  = 0ns 
Min Gnt  = 255ns 
PCI Int Pin = INT A 
Interrupt line = 5 
CPU Interrupt = 5h 
Capabilities Pointer = dch 
Capability ID  = 1h - Power Management 
Capabilities   = c822h - 28002000h 
Capability ID  = 7h - PCI-X 
Capabilities   = 2h - 400000h 
Device Dependent Registers: 
0x040: 0000 0000 0000 0000 0000 0000 0000 0000 
... 
0x0d0: 0000 0000 0000 0000 0000 0000 01e4 22c8 
0x0e0: 0020 0028 0700 0200 0000 4000 0000 0000 
0x0f0: 0500 8000 0000 0000 0000 0000 0000 0000 

和 'nicinfo' 输出:

wm1: 
    INTEL 82544 Gigabit (Copper) Ethernet Controller 

    Physical Node ID ........................... 000E0C C5F6DD 
    Current Physical Node ID ................... 000E0C C5F6DD 
    Current Operation Rate ..................... 100.00 Mb/s full-duplex 
    Active Interface Type ...................... MII 
    Active PHY address ....................... 0 
    Maximum Transmittable data Unit ............ 1500 
    Maximum Receivable data Unit ............... 0 
    Hardware Interrupt ......................... 0x5 
    Memory Aperture ............................ 0xfebc0000 - 0xfebdffff 
    Promiscuous Mode ........................... Off 
    Multicast Support .......................... Enabled 

感谢您的阅读!

+1

'问题是recv()仅在系统的每个计时器滴答时检查是否有新的数据包可用' - 为什么会这样做?我不知道任何QNX, - 网络驱动程序不能正常工作吗?中断驱动程序应该设置一个事件/信号量并通过操作系统退出,这样就可以立即设置recv()线程。应该不需要任何“等到计时器打勾” - 这是无望的 - 也可以使用协作轮询循环:( – 2012-08-08 16:44:39

+0

像Martin提到的实现细节可能因驱动程序和卡的特定型号而异,但您没有 – 2012-08-08 17:12:04

+0

@MartinJames和Ben Voigt:对不起,我没有意识到我的问题可能与驱动程序有关,'nicinfo'表示“INTEL 82544千兆位(铜缆)以太网控制器”和“pci -vvv”输出“供应商ID = 8086h,英特尔公司 设备ID = 107ch,82541PI千兆位以太网控制器“ – jan 2012-08-09 10:46:31

回答

0

你的UDP数据包有多大?如果数据包的大小很小,您将通过将更多的数据包装到单个数据包中并降低传输速率来获得更高的效率。

0

我怀疑中断服务路由(ISR)没有屏蔽中断。也许它是为边缘敏感而设计的,中断是电平敏感的。

1

我很不清楚为什么声明“问题是recv()只在系统的每个计时器滴答时检查是否有新的数据包可用,计时器滴答通常为1ms。对于先发制人的操作系统,将是真实的。系统配置中必须有一些东西,或者网络协议栈实现有一些问题。

几年前,当我在为雅虎BB日本公司工作一些IPTV STB项目时,我在RTP接收中遇到了问题。问题不在于延迟或抖动,而在于我们添加了一些NDS算法后STB的整体系统性能。我们使用vxWorks,并且vxWorks支持以太网钩子接口,每次驱动程序接收到以太网数据包时都会调用它。

我挂接一个API到它,并直接解析UDP从指定的端口从以太网数据包直接。当然,我们有一些假设,没有碎片,这是由性能问题的网络设置保证。也许你也可以检查一下,看你是否可以在QNX以太网驱动程序中获得相同的钩子。至少你发现如果抖动来自司机或不。

0

对不起,我晚了一点,但我遇到了你的问题,看到它与我遇到的情况类似。除了硬件中断之外,您可以尝试使用信号进行软件中断。 QNX在这里有一些文档:http://www.qnx.com/developers/docs/qnx_4.25_docs/qnx4/sysarch/microkernel.html#IPCSIGNALS。我当时使用CentOS,但理论是一样的。根据http://www.qnx.com/developers/docs/6.3.0SP3/neutrino/lib_ref/s/socket.html,您可以使用ioctl()为给定文件描述符的SIGIO信号设置一个接收组...在您的情况下是一个UDP套接字。当套接字有数据准备好读取时,SIGIO信号被发送到由ioctl()指示的进程。使用sigaction()告诉操作系统使用什么信号处理函数。就你而言,信号处理程序可以从套接字读取数据并将其存储在缓冲区中进行处理。使用pause()暂停进程,直到它处理SIGIO信号。当信号处理程序返回时,进程将会唤醒,您可以处理缓冲区中的数据。 这应该允许您在处理数据时无需处理定时器或硬件中断。有一点需要注意的是,您的系统可以像UDP流量进入一样快地处理这些信号。