Re: pushing the envelope with sockets





Dan Ritchie wrote:

I'm using asynchronous I/O, and in the receive handler I issue another BeginReceiveFrom immediately in order to have an I/O ready to receive as quickly as possible. This works very well, but I find that my CPU usage will

Async IO can potentially avoid spending threads in massively parallel applications, but why would it reduce CPU-load?

suddenly (and apparently randomly) increase dramatically (ie, from < 30% to about 60% on average). I've added performance counters, and identified that

During IO, or changing from blocking to non-blocking IO?

30 vs. 60% of how long? comparing relative CPU-usage doesn't make much sense if it's not known what it's relative to.

Try timing:

- receiving the way you do now
- receiving into a large buffer, but less often -- while still not exceeding the OS-buffer-size, something like:

byte[] large_buf = ...;
while ( true ) {
Receive(large_buf, ...);
Thread.Sleep(TimeSpan.FromSeconds(0.1));
}

Which spends more cpu? (it's not the same as which completes first!)

the majority of the increase in CPU time is spent in the BeginReceiveFrom call. This is surprising to me for a couple of reasons. First, this is a non-blocking call, so I would expect it to return quickly whether data is received or not. I also don't see any corresponding increase/decrease in

BeginReceiveFrom may complete synchronously, or it may need to queue in an IO-completion-port for the next receive. The latter will probably spend more or less CPU (although I haven't measured it).

Have you tried reading synchronously with a very large buffer, just to see how that measures up to your async-IO?

If you re-issue BeginReceive immidiatly you must be allocating a new receive-buffer for each receive. Perhaps a less CPU-intensive approach would be to only have one buffer and process that before re-issuing receive?

either the number packets received per second or the number of reads I complete per second (which tracks very closely to UDP packets/second), so I don't believe the number of BeginReceiveFrom calls I'm making is changing commensurately.

You may be seeing switch-overhead. The faster you BeginReceive, the fewer packages the OS will have queued up for you and the more calls to Begin/End-Receive will be executed.

So my question is, is there anything in the Socket implementation that might be causing this unexpected increase in CPU time? I've looked at BeginReceiveFrom with .Net Reflector, and I'm wondering if perhaps the call to ThreadPool.RegisterWaitForSingleObject might be stalling. I'm issuing on the order of about 3500 I/Os per second, but I don't see my ThreadPool availability being impinged. Any ideas? Thanks.

I would try reading in large chunks instead of small ones if low cpu-usage is the goal, at least just to see if there's a difference.

It's another matter if low latency or efficient usage of the number-of-threads resource is required than if you are trying to minimize CPU-usage.

--
Helge
.



Relevant Pages

  • Re: pushing the envelope with sockets
    ... BeginReceiveFrom immediately in order to have an I/O ready to receive as ... but I find that my CPU usage will ... receiving into a large buffer, but less often -- while still not ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: pushing the envelope with sockets
    ... so it would seem 2.0 does indeed buffer UDP. ... Using async I/O ... receiving on the socket they are received, ... Okay, so during *one* run, the cpu spent increases when input-data is ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: Possible bug in .Net 2.0 udp sockets?
    ... R> I called BeginReceiveFrom() several times on purpose, ... R> SocketState currSocketState = result.AsyncState as SocketState; ... And your app won't miss any data, because after receiving ... If you don't do that, indeed, UDP stack can drop packets. ...
    (microsoft.public.dotnet.framework)