Using the version with my patch, I'm able to easily handle 1500 hits/sec spread over 30 already-connected sockets.
I've got about 50 hits/sec coming from each of those sockets (a limitation I've hit too... I've got a usleep call between each write to the socket, but it doesn't seem able to sleep less than 0.02 seconds.)
This is on a 40-cpu Sun box running Solaris 2.8. I'm not sure of the model number, but it's typical of my companies production server farm.
Here's the problem... I need 1000 sockets sending 1 hit/sec, not 30 sockets sending 50 hits/sec. In the former case, the cpu usage skyrockets, presumably because IO::Multiplex is using select instead of poll. So, I went ahead and switched to IO::Poll, after upgrading to perl 5.6.1, and like my previous change I found that not a whole lot had to be modified.
At this point I'm still performance testing my changes. I need to look at the timeout function, and how it's implemented. There is a loop over every filehandle to check for timeouts that need to be executed, and that loop appears to be consuming about a third of the cpu time. That's really bad, since I've only got a single timeout set on my listen socket. I'm pretty confident that I can find a more efficient way to deal with timeouts; I should have that done next week. I'll send you another diff when I get it.
Doug.
Rob Brown wrote:
Perl modules dudes: We are having big problems with this LIRAZ guy who still will not release control over IO::Multiplex because he cannot be contacted. He is not involved with this version of IO::Multiplex either. Can you reassign cpan author from LIRAZ to BBB for me? Or how can we fix this situation?Douglas: Looks fantastic. I'm reviewing your patch now. I've only been able to get around 50 connections/sec because of some large CPU overhead. I'm starting to maintain it a little more, but I'm not the original author. Bruce is. I think your patch will help. You should see it in version 1.04. I'll let him know, too. Thanks, Rob Brown CPANID: BBB On Thu, 30 May 2002, Douglas Webb wrote:I've been working on a project for my company which requires a daemon process to take in ~1 request/second from 1000 other processes on the same machine, and send those 1000 requests/sec through some parsing and then on to Oracle. The architecture I decided on was to have a single select-based process that would watch 1000 sockets for input, and to pass that input to 20 or so sockets which are connected to forked-off subprocesses. The subprocesses would handle the parsing and DBI stuff. This lets me spend a lot more time dealing with Oracle than I otherwise could. I looked in Network Programming with Perl, and figured that somebody must have already put the examples in there onto CPAN. That's how I found IO::Multiplex. Overall, I'm happy with IO::Multiplex; the testing I've done so far tells me that it'll be able to handle my needs reliably. However, I discovered that it uses way more cpu time than it needs to, due to the use of Tie::RefHash. That module lets you use a reference as a hash key, but pretend that it's still a reference. Normally, the reference is turned into a string, and the string is used as the key. When I ran my program through Devel::DProf, I found that a huge amount of time was being spent in FETCH, NEXTKEY, EXISTS in the Tie::RefHash module. After searching through IO::Multiplex, I found that there were only a couple of places where the hash keys are being used as references (to filehandles.) The rest of the accesses just used them as keys, so the Tie::RefHash was a waste. I added a new key to $self, _handles, to map from the stringified filehandle reference to the real filehandle reference, and I made a few other changes to use the new key only where needed. This gave me about a 20x reduction in the cpu usage under the same request/sec load. Here's the diff for my changes; there aren't many of them. I don't think there are any drawbacks to my approach. Let me know if you have any questions. Doug. bash-2.03$ diff -C 1 Multiplex.orig.pm Multiplex.doug.pm *** Multiplex.orig.pm Mon Feb 4 13:14:03 2002 --- Multiplex.doug.pm Thu May 30 11:04:02 2002 *************** *** 161,163 **** use IO::Multiplex; - use Tie::RefHash; --- 161,162 ---- *************** *** 271,273 **** use Data::Dumper; - use Tie::RefHash; use Carp qw(cluck); --- 270,271 ---- *************** *** 301,304 **** _fhs => {}, _listen => {} } => $package; - tie %{$self->{_fhs}}, "Tie::RefHash"; $self; --- 299,302 ---- _fhs => {}, + _handles => {}, _listen => {} } => $package; $self; *************** *** 353,354 **** --- 351,353 ---- $self->{_fhs}{$fh}{fileno} = fileno($fh); + $self->{_handles}{$fh} = $fh; tie *$fh, "MVModule::MVmux::Handle", $self, $fh; *************** *** 374,375 **** --- 373,375 ---- delete $self->{_fhs}{$fh}; + delete $self->{_handles}{$fh}; untie *$fh; *************** *** 518,520 **** ! grep(!$self->{_fhs}{$_}{listen}, keys %{$self->{_fhs}}); } --- 518,520 ---- ! grep(!$self->{_fhs}{$_}{listen}, values %{$self->{_handles}}); } *************** *** 563,565 **** ! foreach my $fh (keys %{$self->{_fhs}}) { # Avoid creating a permanent empty hash ref for "$fh" --- 563,565 ---- ! foreach my $fh (values %{$self->{_handles}}) { # Avoid creating a permanent empty hash ref for "$fh" *************** *** 797,798 **** --- 797,799 ---- delete $self->{_fhs}{$fh}; + delete $self->{_handles}{$fh}; untie *$fh; *************** *** 800,802 **** $obj->mux_close($self, $fh) if $obj && $obj->can("mux_close"); - delete $self->{_fhs}{$fh}; } --- 801,802 ----