Re: Linux equivalent for ioctlsocket(FIONREAD) on datagram sockets
- From: David Schwartz <davids@xxxxxxxxxxxxx>
- Date: Mon, 9 Mar 2009 18:51:10 -0700 (PDT)
On Mar 9, 6:17 pm, already5cho...@xxxxxxxxx wrote:
Now you are trying to be constructive.
You simply don't like the answer.
However your concentration on the letter of standard prevents you from
understanding the spirit.
Yes, UDP is defined us unreliable. But it also defined as "best
effort". It would be practically useless without the later.
Right, but everything is designed based on the premise that it is
unreliable. You cannot *ever* assume it is reliable.
Now imagine the IP stack the adheres to both the letter and the spirit
of the standard. Imagine fast CPU/Memory/IO bus. Imagine slow physical
line. Please take into account that for modern CPUs/memory/IO-Bus even
1GBe is a "slow line". Imagine that fast CPU sends a burst of UDP
datagrams which is longer than SEND_BUFFER through blocking socket.
That would be a bug. The sending application is responsible for
transmit pacing in a UDP application.
Now what the IP stack/packet driver that adheres to the "best effort"
spirit of UDP standard should do in that particular case? Drop the
packet? No way, that's against the spirit. The correct way would be
blocking a clling thread until the NIC hardware (probably through DMA)
reads one or more packets from socket's send buffer freeing up space
for the next one. Comprende?
Right, but you can't design based on that. The exact same problem can
happen one hop away on the other side of a router. So what point is
there in going to special effort to solve this one case when it leaves
another version of the exact same problem unsolved?
With UDP, you need a general solution to bottlenecks that can occur
anywhere. There is little point to special solutions to special
bottlenecks, unless you have some special way to know that that's the
only problem you are going to have.
The APIs and interfaces are designed for the general case.
What is the best way to receive fast UDP stream (order of 20K to 50K
packets per second) while dropping as few packets as possible?
Obviously, it depends on the operating system.
On Windows the [pseudo]code presented in my original post easily
achieves packet error rate of ~1E-7 but hits the wall when we try to
do better. And on Windows when you hit the wall.... well, you hit the
wall.
On Windows, posting lots of overlapped I/O requests and using a pool
of threads is the best you can do.
On Linux (Ubuntu 8.10 x64) so far I see packet error rates in excess
of 1E-5. And yes, I tried both blocking and non-blocking sockets. Non-
blocking variant significantly reduces the CPU load but, at least on
fast computers, makes no material difference to the error rates. The
fact that the my current Linux results are so horribly bad leaves the
hope that I am doing something wrong... May be, I should try scatter-
gather read? Or something else?
Set the receive queue as large as you can. Keep a thread blocked on
'recvmsg'. Make sure that this thread does as little work as possible
before it gets back to 'recvmsg'. Keep your own internal queue of
received datagrams.
Keep a pool of free memory chunks so you don't block in the normal
allocator. Pre-allocate, say, 1,000 packet buffers with the necessary
space to form them into a linked list. Your loop looks like this:
1) Receive a UDP packet into my pre-allocated buffer.
2) Add it to my own linked list of packets.
3) Try to acquire the lock on the master linked list of packets. If
fewer than 10 packets received, do so non-blocking. If more than 10,
do so blocking.
4) If we failed to acquire the lock, jump to step 1.
5) Add our linked list of packets to the end of the system's linked
list.
6) Release the lock.
7) Go to step 1.
Keep all memory allocation out of the fast path. Do not block on the
linked list that is shared with other threads unless too much data has
backed up.
Note that you basically cannot do this with a single thread. There are
simply too many ways you can unexpectedly block.
I understand that quite a few people would try to suggest that I
shouldn't want :( to receive UDP datagrams at low error rate. All
these people are welcome to say it right here but sincerely I don't
promise a polite response.
It's definitely bad to allow your code to introduce extra packet loss.
You should definitely do your best to avoid losing data that has gone
to all the trouble to get to your system.
DS
.
- References:
- Linux equivalent for ioctlsocket(FIONREAD) on datagram sockets
- From: already5chosen
- Re: Linux equivalent for ioctlsocket(FIONREAD) on datagram sockets
- From: David Schwartz
- Re: Linux equivalent for ioctlsocket(FIONREAD) on datagram sockets
- From: already5chosen
- Re: Linux equivalent for ioctlsocket(FIONREAD) on datagram sockets
- From: David Schwartz
- Re: Linux equivalent for ioctlsocket(FIONREAD) on datagram sockets
- From: already5chosen
- Re: Linux equivalent for ioctlsocket(FIONREAD) on datagram sockets
- From: David Schwartz
- Re: Linux equivalent for ioctlsocket(FIONREAD) on datagram sockets
- From: already5chosen
- Linux equivalent for ioctlsocket(FIONREAD) on datagram sockets
- Prev by Date: Re: Linux equivalent for ioctlsocket(FIONREAD) on datagram sockets
- Next by Date: Re: Should I get Solaris or Fedora for a future startup?
- Previous by thread: Re: Linux equivalent for ioctlsocket(FIONREAD) on datagram sockets
- Next by thread: Re: Should I get Solaris or Fedora for a future startup?
- Index(es):
Relevant Pages
|