Subject: IPC Test program
To: None <current-users@sun-lamp.cs.berkeley.edu>
From: Mark P. Gooderum <mark@aggregate.com>
List: current-users
Date: 05/06/1994 14:23:23
After 10 requests already for this I figured it was worth posting.
If someone wants to implement some of the unimplmented SysV IPC
testing, go to it.
There is a -z debug flag as well. Building on SysVen will usually
require -lsocket (and maybe -lnsl). The formatting is kind of futzed
because I use 4 char tab stops. Use indent in emacs to fix it. If
you use vi, that's you're problem ;-).
Change the value of BASE_MSG to change the total byte volume to get
long enough runs to have good numbers and short enough runs to
go home. These numbers are good for 486 up to slow Suns. Faster
boxes and screamers require much larger numbers to run long enough to get
good timings.
-Mark
------
/*
* ipc.c - A program to measure local IPC speed.
*/
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/signal.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/*
* Constants...
*/
#define BASE_MSG (1048576 / 16)
#undef TRUE
#undef FALSE
#define TRUE 1
#define FALSE 0
/*
* Type Declarations...
*/
typedef struct ipc_stat {
int io_size; /* # of bytes per I/O op */
int io_total; /* Total # of bytes done */
int millisec; /* # millsecsonds to do types for all I/O */
double io_kps; /* K bytes per/second I/O speed */
double msg_ps; /* # messages per second */
} ipc_stat;
/*
* Variables...
*/
int size_list[] = { 16, 256, 1024, 4096, -1 };
ipc_stat stat_tab[100];
char write_buf[4096],
read_buf[4096];
int sock_domain_stream = FALSE;
int sock_domain_dgram = FALSE;
int sock_tcp = FALSE;
int sock_udp = FALSE;
int msg_port = FALSE;
int stream_pipe = FALSE;
int debug_flag = FALSE;
/*
* Socket stuff...
*/
struct sockaddr_in maddr, saddr;
struct sockaddr aaddr;
/*
* Support functions...
*/
void usage(void);
void print_stats(char *, ipc_stat *);
ipc_stat *do_io(int *, ipc_stat *);
int sock_master(int);
int sock_stream(int);
/*
* Measurement functions...
*/
ipc_stat *do_sock_domain_stream();
ipc_stat *do_sock_domain_dgram();
ipc_stat *do_sock_udp();
ipc_stat *do_sock_tcp();
ipc_stat *do_stream_pipe();
/*
* Support functions...
*/
void main(int argc, char *argv[])
{
ipc_stat *stats;
char opt;
/*
* Check for args...
*/
if (argc <= 1) {
usage();
exit(0);
}
/*
* Parse our argument list...
*/
while ((opt = getopt(argc, argv, "adDptumz")) != EOF) {
switch(opt) {
case 'a':
sock_domain_stream = TRUE;
sock_domain_dgram = TRUE;
sock_tcp = TRUE;
sock_udp = TRUE;
stream_pipe = TRUE;
msg_port = TRUE;
break;
case 'd':
sock_domain_stream = TRUE;
break;
case 'D':
sock_domain_dgram = TRUE;
break;
case 't':
sock_tcp = TRUE;
break;
case 'u':
sock_udp = TRUE;
break;
case 'm':
msg_port = TRUE;
break;
case 'p':
stream_pipe = TRUE;
break;
case 'z':
debug_flag = TRUE;
break;
default:
usage();
exit(1);
} /* switch */
} /* while */
/*
* Do our measurements and print the results for each
* IPC method.
*/
if (sock_domain_stream) {
stats = do_sock_domain_stream();
print_stats("Stream Domain Sockets", stats);
}
if (sock_domain_dgram) {
stats = do_sock_domain_dgram();
print_stats("Datagram Domain Sockets", stats);
}
if (sock_udp) {
stats = do_sock_udp();
print_stats("UDP Sockets", stats);
}
if (sock_tcp) {
stats = do_sock_tcp();
print_stats("TCP Sockets", stats);
}
if (msg_port) {
printf("Warning, '-m' - SysV Messages, currently not supported.\n");
}
if (stream_pipe) {
stats = do_stream_pipe();
print_stats("Stream Pipe", stats);
}
} /* main() */
/*
* usage()
*/
void usage(void)
{
printf("\nUsage: ipc [-dtums]\n");
printf("\t-a\t-Time all.\n");
printf("\t-d\t-Time Stream Domain Sockets\n");
printf("\t-D\t-Time Datagram Domain Sockets\n");
printf("\t-t\t-Time TCP Sockets\n");
printf("\t-u\t-Time UDP Sockets\n");
printf("\t-m\t-Time Message Ports\n");
printf("\t-p\t-Time Stream Pipes\n");
printf("\n");
}
/*
* do_sock_domain_stream()
*/
ipc_stat *do_sock_domain_stream(void)
{
ipc_stat *retval;
int fds[2];
int x;
/*
* Initialize some variables.
*/
retval = stat_tab;
/*
* Loop on I/O sizes calling do_io()...
*/
for (x = 0; size_list[x] != -1; x++) {
retval[x].io_size = size_list[x];
if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == -1) {
perror("socketpair(SOCK_STREAM) failed");
retval[0].io_size = -1;
return(NULL);
}
do_io(fds, &retval[x]);
close(fds[0]);
close(fds[1]);
}
retval[x].io_size = -1;
/*
* And return...
*/
return(retval);
} /* do_sock_domain_stream() */
/*
* do_sock_domain_dgram()
*/
ipc_stat *do_sock_domain_dgram(void)
{
ipc_stat *retval;
int fds[2];
int x;
/*
* Initialize some variables.
*/
retval = stat_tab;
/*
* Loop on I/O sizes calling do_io()...
*/
for (x = 0; size_list[x] != -1; x++) {
retval[x].io_size = size_list[x];
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, fds) == -1) {
perror("socketpair(SOCK_DGRAM) failed");
retval[0].io_size = -1;
return(NULL);
}
do_io(fds, &retval[x]);
close(fds[0]);
close(fds[1]);
}
retval[x].io_size = -1;
/*
* And return...
*/
return(retval);
} /* do_sock_domain_dgram() */
/*
* do_sock_tcp()
*/
ipc_stat *do_sock_tcp(void)
{
ipc_stat *retval;
int fds[2];
int x, ts, ssize;
/*
* Initialize some variables.
*/
ssize = sizeof(aaddr);
retval = stat_tab;
/*
* Loop on I/O sizes calling do_io()...
*/
for (x = 0; size_list[x] != -1; x++) {
retval[x].io_size = size_list[x];
/*
* Initialize our fd's...
*/
if ((ts = sock_master(SOCK_STREAM)) < 0) {
return(NULL);
}
if ((fds[1] = sock_slave(SOCK_STREAM)) < 0) {
return(NULL);
}
if ((fds[0] = accept(ts, &aaddr, &ssize)) < 0) {
return(NULL);
}
do_io(fds, &retval[x]);
close(fds[0]);
close(fds[1]);
close(ts);
}
retval[x].io_size = -1;
/*
* And return...
*/
return(retval);
} /* do_sock_tcp() */
/*
* do_sock_udp()
*/
ipc_stat *do_sock_udp(void)
{
ipc_stat *retval;
int fds[2];
int x, ts, ssize;
/*
* Initialize some variables.
*/
ssize = sizeof(aaddr);
retval = stat_tab;
/*
* Initialize our fd's...
*/
/*
* Loop on I/O sizes calling do_io()...
*/
for (x = 0; size_list[x] != -1; x++) {
retval[x].io_size = size_list[x];
/*
* Initialize our fd's...
*/
if ((fds[1] = sock_master(SOCK_DGRAM)) < 0) {
return(NULL);
}
if ((fds[0] = sock_slave(SOCK_DGRAM)) < 0) {
return(NULL);
}
do_io(fds, &retval[x]);
close(fds[0]);
close(fds[1]);
close(ts);
}
retval[x].io_size = -1;
/*
* And return...
*/
return(retval);
} /* do_sock_udp() */
/*
* do_stream_pipe()
*/
ipc_stat *do_stream_pipe(void)
{
ipc_stat *retval;
int fds[2];
int x;
/*
* Initialize some variables.
*/
retval = stat_tab;
/*
* Loop on I/O sizes calling do_io()...
*/
for (x = 0; size_list[x] != -1; x++) {
retval[x].io_size = size_list[x];
if (pipe(fds) == -1) {
perror("socketpair(SOCK_STREAM) failed");
retval[0].io_size = -1;
return(NULL);
}
do_io(fds, &retval[x]);
close(fds[0]);
close(fds[1]);
}
retval[x].io_size = -1;
/*
* And return...
*/
return(retval);
} /* do_stream_pipe() */
/*
* do_io()
*
* Do the I/O on a given descriptor (writing) and measure it.
*/
ipc_stat *do_io(int *fd, ipc_stat *istat)
{
struct timeval begtime, endtime;
register int x;
register int num_msgs;
int pid, ret;
int size;
int tot_size;
register int fd1 = fd[0],
fd2 = fd[1];
size = istat->io_size;
num_msgs = BASE_MSG / (int) log2(size);
tot_size = num_msgs * size;
if (debug_flag) {
printf("do_io(): Size=%d, msgs=%d\n", size, num_msgs);
}
if ((pid = fork()) == -1) {
return(NULL);
}
gettimeofday(&begtime);
if (pid > 0) {
close(fd2);
for (x = 0; x < num_msgs ; x++) {
writen(fd1, write_buf, size);
}
}
if (pid == 0) {
close(fd1);
for (x = 0; x < num_msgs ; x++) {
readn(fd2, read_buf, size);
}
_exit(0);
}
kill(pid, SIGTERM);
do {
ret = wait(NULL);
} while (ret != pid);
gettimeofday(&endtime);
istat->io_total = tot_size;
istat->millisec = (((endtime.tv_sec * 1000) + (endtime.tv_usec / 1000)) -
((begtime.tv_sec * 1000) + (begtime.tv_usec / 1000)));
istat->io_kps = ((double) istat->io_total) /
((double) istat->millisec) * 1000.0
/ 1024.0;
istat->msg_ps = ((double) num_msgs * 1000.0) / ((double)(istat->millisec));
return(istat);
} /* do_io() */
/*
* print_stats()
*/
void print_stats(char *io_type, ipc_stat *stats)
{
int x;
printf("Timing for %s:\n", io_type);
printf("--------------------------------\n");
for (x = 0; stats[x].io_size != -1; x++) {
printf("Size: %d,\tKB p/sec: %.2f,\tMsgs p/sec: %.2f\n",
stats[x].io_size, stats[x].io_kps, stats[x].msg_ps);
}
printf("\n");
} /* print_stats() */
/*
* readn()
*
* Read n bytes from a stream socket. A stream socket may return 0
* read but still have I/O because of buffering constraints.
*/
int readn(fd, parg, nbytes)
int fd;
void *parg;
int nbytes;
{
char *ptr= parg;
int nleft,
nread,
ntot = 0;
/*
* Loop until we read() nbytes bytes or until we get an error (which
* may be EWOULDBLOCK if it's a non-blocking socket.
*/
nleft = nbytes;
while (nleft > 0) {
nread = read(fd, ptr, nleft);
if (nread < 0) {
/*
* If we have read some bytes throw away the error and return what
* we have read, otherwise return the error.
*/
return(ntot > 0 ? ntot : nread);
} else if (nread == 0) {
break;
}
ntot += nread;
nleft -= nread;
ptr += nread;
}
return(nbytes - nleft);
} /* readn() */
/*
* writen()
*
* Write n bytes to a stream socket.
*/
int writen(fd, parg, nbytes)
int fd;
void *parg;
int nbytes;
{
char *ptr = parg;
int nleft = nbytes,
ntally = 0,
nwritten;
while (nleft > 0) {
nwritten = write(fd, ptr, nleft);
if (nwritten < 0) {
return(ntally > 0 ? ntally : nwritten);
} else if (nwritten == 0) {
break;
}
nleft -= nwritten;
ntally += nwritten;
ptr += nwritten;
}
return(nbytes - nleft);
} /* writen() */
/*
* sock_master()
*
* This function opens the master half of a Unix socket.
* We use a sock of the name <jobid.iosock>
*/
static int sock_master(type)
int type;
{
int master_fd;
int alen;
int retval;
struct hostent *host;
if ((master_fd = socket(AF_INET, type, 0)) < 0) {
return(-1);
}
memset(&maddr, 0, sizeof(maddr));
maddr.sin_family = AF_INET;
maddr.sin_addr.s_addr = htonl(INADDR_ANY);
maddr.sin_port = 0;
alen = sizeof(maddr);
if (bind(master_fd, &maddr, alen) < 0) {
close(master_fd);
return(-1);
}
if (getsockname(master_fd, &saddr, &alen) < 0) {
close(master_fd);
return(-1);
}
if ((host = gethostbyname("localhost")) == NULL) {
return(-1);
}
memcpy(&saddr.sin_addr, host->h_addr_list[0], host->h_length);
maddr.sin_port = saddr.sin_port;
if (type == SOCK_STREAM) {
if ((retval = listen(master_fd, 5)) < 0) {
return(-1);
}
}
return(master_fd);
} /* sock_master() */
/*
* sock_slave()
*
* This function opens the slave half of a Unix socket.
*/
static int sock_slave(type)
int type;
{
int slave_fd;
int alen;
if ((slave_fd = socket(AF_INET, type, 0)) < 0) {
return(-1);
}
alen = sizeof(saddr);
if (connect(slave_fd, &saddr, alen) < 0) {
close(slave_fd);
return(-1);
}
if (getsockname(slave_fd, &saddr, &alen) < 0) {
close(slave_fd);
return(-1);
}
return(slave_fd);
} /* sock_slave() */
----- End Included Message -----
------------------------------------------------------------------------------