Code owners
Assign users and groups as approvers for specific file changes. Learn more.
udpbwtest.c 5.15 KiB
/* udpbwtest: a simple bandwidth test
*
* To test all-to-all communication, we simply open up a
* UDP socket and repeat the following:
*
* 1. Send a packet to a random host if possible
* 2. Receive a packet if possible
* 3. Periodically report our I/O bandwidth
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <strings.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <sys/time.h>
#include <poll.h>
#include <signal.h>
enum { Port=12345 };
/* Handy utility functions */
int bindAddr( int fd, long addr, u_short port ) {
/* Easy interface to bind */
struct sockaddr_in sa;
bzero( &sa, sizeof( sa ) );
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = htonl( addr );
sa.sin_port = htons( port );
return bind( fd, ( struct sockaddr * )&sa, sizeof( sa ) );
}
int udpSocket( u_short port ) {
/* Easy interface to making a UDP socket */
int fd = socket( AF_INET, SOCK_DGRAM, 0 );
if ( fd < 0 ) { return fd; }
int err = bindAddr( fd, INADDR_ANY, port );
if ( err < 0 ) { return err; }
return fd;
}
ssize_t sendBytes( int sock, char *outbuf, size_t bufsize,
struct in_addr *addr, u_short port ) {
/* Simpler sendto */
struct sockaddr_in sa;
int err;
bzero( &sa, sizeof( sa ) );
sa.sin_family = AF_INET;
sa.sin_addr = *addr;
sa.sin_port = htons( port );
err = sendto( sock, outbuf, bufsize, 0, (const struct sockaddr *) &sa,
sizeof( sa ) );
if ( err < 0 ) { perror( "sendto:" ); }
return err;
}
ssize_t recvBytes( int sock, char *inbuf, size_t bufsize,
struct in_addr *addr) {
/* Simpler recvfrom */
struct sockaddr_in sa;
socklen_t saLen = sizeof( sa );
ssize_t len;
len = recvfrom( sock, inbuf, bufsize, 0, (struct sockaddr *) &sa, &saLen );
if ( len >= 0 ) {
assert( saLen == sizeof( sa ) );
*addr = sa.sin_addr;
}
else { perror( "recvfrom:" ); }
return len;
}
int readable( int fd ) {
/* Poll a single file descriptor for reading */
struct pollfd fds = { fd, POLLIN, POLLIN };
int result = poll( &fds, 1, 0 );
/* True if there is one readable descriptor */
return ( result == 1 );
}
int writable( int fd ) {
/* Poll a single file descriptor for writing */
struct pollfd fds = { fd, POLLOUT, POLLOUT };
int result = poll( &fds, 1, 0 );
/* True if there is one writable descriptor */
return ( result == 1 );
}
int poll1( int fd, int flags, int ms ) {
/* Call poll on a single descriptor */
struct pollfd fds[] = { { fd, flags, 0 } };
return poll( fds, 1, ms );
}
int waitReadable( int fd, int ms ) { return poll1( fd, POLLIN, ms ); }
int waitWritable( int fd, int ms ) { return poll1( fd, POLLIN, ms ); }
int waitReadableOrWritable( int fd, int ms ) {
return poll1( fd, POLLIN | POLLOUT, ms );
}
/* Timer support */
int alarm = 0;
void handleAlarm( int sig) { alarm = 1; }
void startTimer( int seconds) {
struct itimerval v;
v.it_interval.tv_sec = seconds;
v.it_interval.tv_usec = 0;
v.it_value = v.it_interval;
signal( SIGALRM, handleAlarm );
setitimer( ITIMER_REAL, &v, 0 );
}
void startOneSecondTimer() { startTimer( 1 ); }
void stopTimer() {
struct itimerval v;
bzero( &v, sizeof v );
setitimer( ITIMER_REAL, &v, 0 );
}
/* Actual program */
void bwtest( int sock, struct in_addr *hosts, int hostCount ) {
/* Test our bandwidth, by receiving whatever we get, and sending
* randomly to a set of hosts */
char outbuf[ 1024 ];
char inbuf[ 1024 ];
time_t seconds = time( 0 );
uint64_t b, bytes;
uint64_t inbytes = 0, outbytes = 0;
int i;
for ( i = 0; i < sizeof( outbuf ); i++ ) { outbuf[ i ] = i % 255; }
while ( 1 ) {
size_t addr_len;
struct in_addr addr = hosts[ random() % hostCount ];
/* Wait until we have something to do. */
waitReadableOrWritable( sock, 0 );
/* Receive some bytes */
for ( b = 0; b < 10 && readable( sock ); b += 1 ) {
bytes = recvBytes( sock, inbuf, sizeof( inbuf ), &addr );
inbytes += bytes;
}
/* Send some bytes */
for ( b = 0; b < 10 && writable(sock); b += 1 ) {
bytes = sendBytes( sock, outbuf, sizeof( outbuf ),
&addr, Port );
outbytes += bytes;
}
/* Periodically report bandwidth */
if ( alarm ) {
alarm = 0;
seconds++;
printf("%d s: in %.2f Mbps, out %.2f Mbps\n",
seconds, 8.0*inbytes/1e6, 8.0*outbytes/1e6 ); fflush( stdout );
inbytes = outbytes = 0;
}
}
}
int main( int argc, char *argv[] ) {
struct in_addr start, *hosts, addr;
int count, sock, i;
if ( argc < 2 ) {
fprintf( stderr, "usage: %s host...\n", argv[ 0 ] );
exit( 1 );
}
count = argc - 1;
hosts = (struct in_addr *) malloc( count * sizeof( struct in_addr ) );
if ( hosts == NULL ) { perror( "malloc:" ); exit( 1 ); }
for ( i = 0; i < count; i++ )
inet_aton( argv[ i + 1 ], &hosts[ i ] );
sock = udpSocket( Port );
if ( sock < 0 ) { perror( "udpSocket:" ); exit( 1 ); }
startOneSecondTimer();
bwtest( sock, hosts, count ); /* Never returns for now... */
stopTimer();
}