#!/usr/bin/perl use warnings; use strict; use constant DEFAULT_NUM_CLIENTS => 200_000; use constant DEFAULT_SUBNET => '127.0.0'; use constant DEFAULT_PORT => 7500; use constant SLEEP_TIME => 0; use constant MAX_SOCKETS_PER_ADDR => 25000; use constant CLIENT_AVG_MSG_TIME => 30; use IO::Socket::INET; use IO::Epoll; use Time::HiRes qw(time sleep); use POSIX; our $SUBNET = shift || DEFAULT_SUBNET; our $PORT = shift || DEFAULT_PORT; our $NUM_CLIENTS = shift || DEFAULT_NUM_CLIENTS; our $RUN_TIME = shift || undef; $| = 1; our $epoll; ($epoll = epoll_create($NUM_CLIENTS)) > 0 or die "Couldn't create epoller: $!\n"; our @sock; my $numAddrs = $NUM_CLIENTS / MAX_SOCKETS_PER_ADDR + 1; my $clientsLeft = $NUM_CLIENTS; my $i = 0; foreach my $addrPart (1 .. $numAddrs) { my $addr = $SUBNET . '.' . $addrPart; foreach my $addrConn (1 .. min($clientsLeft, MAX_SOCKETS_PER_ADDR)) { $sock[$i] = IO::Socket::INET->new(PeerHost => $addr, PeerPort => $PORT, Protocol => 'tcp', ) or die "Couldn't create socket to $addr:$PORT: $!\n"; print { $sock[$i] } "0 0 0 0 0\r\n"; epoll_ctl($epoll, EPOLL_CTL_ADD, fileno($sock[$i]), EPOLLIN) == 0 or die "Couldn't add FD to epoll: $!\n"; print $i," at $addr:",$sock[$i]->sockport(),"\n"; sleep(SLEEP_TIME); $i++; handle_events(); } $clientsLeft -= MAX_SOCKETS_PER_ADDR; } my $count = 0; my $recv_count = 0; my $start = time; $SIG{INT} = $SIG{ALRM} = \&print_results; if ($RUN_TIME) { print "Running for $RUN_TIME seconds\n"; alarm($RUN_TIME); } while(1) { my $whichsock = rand(@sock); $count++; POSIX::write(fileno($sock[$whichsock]),"P\r\n",3); handle_events(); # sleep(CLIENT_AVG_MSG_TIME / $NUM_CLIENTS); } sub print_results { my $end = time; my $elapsed = $end - $start; print "Results for $NUM_CLIENTS:\n"; print "\tSent $count events and received $recv_count in ",$elapsed," seconds.\n"; print "\t",$count/$elapsed," sends/sec, ", $recv_count/$elapsed," recvs/sec.\n"; foreach my $sock (@sock) { close($sock) or warn "Couldn't close socket: $!\n"; } exit(0); } sub handle_events { my $events = epoll_wait($epoll, $NUM_CLIENTS, 0) or die "Couldn't epoll_wait: $!\n"; foreach my $ev (@$events) { my $buf; my $ret = POSIX::read($ev->[0],$buf,8192) or warn "sysread failed on FD $ev->[0]: $!\n"; my $lines = ($buf =~ tr/\n/\n/); $recv_count += $lines; } } sub min { return $_[0] < $_[1] ? $_[0] : $_[1]; } sub max { return $_[0] > $_[1] ? $_[0] : $_[1]; }