Freitag, 29. Februar 2008

Better than usleep ...

What do you do when a socket read or write returns EAGAIN/EWOULDBLOCK?

Tests showed that an immediate attempt to read again also returns the same error code.
So, what I did was to implement a usleep() for 10 milliseconds (shorter times are not possible on Solaris systems) and then try again. This works.
But nowadays 10 milliseconds is far too much: A process that can handle 5000 msgs/s would get through 50 messages in this time...

Now I learned about the function yield() (sched_yield() on Linux). This function tells the scheduler to look for another process to execute (in simple words).
I replaced the usleep() call with a call to yield(), of course hoping that the calling process would be activated by the scheduler earlier than when usleep() was called.
And test showed that it works: A process that handled 2'500-3'000 msgs/s before managed more than 7'500 messages afterwards!

So, if you have a process that is blocked somehow and should wait for a change of state, specially when this change of state is caused by another process, call yield()!

Montag, 25. Februar 2008

Socket read

A few days ago one of our customers complained that the connection loss notification did not work. To cut a long story short, the read() function still returned 0 and 0 bytes read, even though the socket was closed long ago.
Wouldn't you expect the read() function to return some kind of error after some time?
Well, luckily both client and server were running on the same system, and the pid of the server is stored in the shared memory, so the client can check if the server is still running. With this change the client detects connection losses within a matter of microseconds.

Ok, the problem is solved, but still I'd like the read() function to return an error code if the socket was closed, especially if the client and server are running on the same system?!?

Mittwoch, 20. Februar 2008

Virtual Function Table

Every now and then you read in books or magasins that C++ gets slow when virtual functions are used, because it must be determined at run-time which function must be executed.
Well, I wrote a set of classes and a test program to measure the performance of the following different implementations:
  • Class without any virtual function.
  • Class with a virtual destructor.
  • Class where the function that's called is defined virtual.
  • Class with a virtual destructor and the function defined as virtual.
  • Class derived from a base class (interface-like) which defined the function as pure virtual, and the implementation in the derived class.
Since the test function itself didn't do much I had to call it several million times to get a run-time in seconds for every test. And the result was: No difference at all, every type of implementation showed the same run-time behaviour, the difference between the different measured times was less than 1 percent.

So, use base classes and virtual functions and all the fancy features that C++ offers!