Return to BSD News archive
Xref: sserve comp.unix.internals:7637 comp.unix.solaris:22170 comp.unix.sys5.r4:8264 comp.unix.bsd:14795 Path: sserve!newshost.anu.edu.au!harbinger.cc.monash.edu.au!bunyip.cc.uq.oz.au!munnari.oz.au!constellation!paladin.american.edu!europa.eng.gtefsd.com!library.ucla.edu!csulb.edu!nic-nac.CSU.net!usc!math.ohio-state.edu!cs.utexas.edu!chpc.utexas.edu!news.utdallas.edu!wupost!bigfoot.wustl.edu!tango.cs.wustl.edu!not-for-mail From: schmidt@tango.cs.wustl.edu (Douglas C. Schmidt) Newsgroups: comp.unix.internals,comp.unix.solaris,comp.unix.sys5.r4,comp.unix.bsd Subject: Re: DLPI Vs BSD Sockets Vs Sys V TLI Date: 25 Aug 1994 18:26:03 -0500 Organization: Computer Science Department, Washington University. Lines: 1083 Distribution: inet Message-ID: <33j9ab$bnq@tango.cs.wustl.edu> References: <33ft3u$mn3@news.tamu.edu> <33iecq$leg@crl2.crl.com> <1994Aug25.165610.18709@noao.edu> NNTP-Posting-Host: tango.cs.wustl.edu In article <1994Aug25.165610.18709@noao.edu>, W. Richard Stevens <rstevens@noao.edu> wrote: ++ Have you ever benchmarked sockets versus TLI on Solaris? Has anyone? ++ How about just changing ttcp to use TLI instead of sockets and proving ++ or disproving this myth? I've ported ttcp to use TLI on Solaris. I just ran a test using loop-back mode on my SPARCstation 20 running Solaris 2.3 to compare the two. Here are the results from the socket version (no additional options): ---------------------------------------- % ./sock-ttcp -s -r -f m -p 5000 ttcp-r: buflen=8192, nbuf=2048, align=16384/0, port=5000 tcp ttcp-r: socket ttcp-r: accept from 127.0.0.1 ttcp-r: 16777216 bytes in 2.24 real seconds = 57.16 Mbit/sec +++ ttcp-r: 2049 I/O calls, msec/call = 1.12, calls/sec = 915.07 ttcp-r: 0.0user 0.7sys 0:02real 34% ---------------------------------------- And here what I get with the TLI version (also no additional options): ---------------------------------------- % ./tli-ttcp -s -r -f m -p 5002 ttcp-r: buflen=8192, nbuf=2048, align=16384/0, port=5002 tcp ttcp-r: t_open ttcp-r: t_accept from 127.0.0.1 ttcp-r: 16777216 bytes in 2.37 real seconds = 54.00 Mbit/sec +++ ttcp-r: 2049 I/O calls, msec/call = 1.18, calls/sec = 864.44 ttcp-r: 0.1user 0.8sys 0:02real 42% ---------------------------------------- Although the results aren't strikingly different it is interestingly to note that the socket version of TTCP is faster than the TLI version (I ran this several times and the socket version consistently outperformed the TLI version). Moreover, the percentage utilization of the CPU is also higher for the TLI version. I think this confirms Rich's intuition that sockets are not inherently slower than TLI. BTW, I've posted the TLI-based version of TTCP below. Please let me know if you have any comments. Thanks, Doug ---------------------------------------- /* * T T C P . C * * Test TCP connection. Makes a connection on port 5001 * and transfers fabricated buffers or data copied from stdin. * * Usable on 4.2, 4.3, and 4.1a systems by defining one of * BSD42 BSD43 (BSD41a) * Machines using System V with BSD sockets should define SYSV. * * Modified for operation under 4.2BSD, 18 Dec 84 * T.C. Slattery, USNA * Minor improvements, Mike Muuss and Terry Slattery, 16-Oct-85. * Modified in 1989 at Silicon Graphics, Inc. * catch SIGPIPE to be able to print stats when receiver has died * for tcp, don't look for sentinel during reads to allow small transfers * increased default buffer size to 8K, nbuf to 2K to transfer 16MB * moved default port to 5001, beyond IPPORT_USERRESERVED * make sinkmode default because it is more popular, * -s now means don't sink/source * count number of read/write system calls to see effects of * blocking from full socket buffers * for tcp, -D option turns off buffered writes (sets TCP_NODELAY sockopt) * buffer alignment options, -A and -O * print stats in a format that's a bit easier to use with grep & awk * for SYSV, mimic BSD routines to use most of the existing timing code * Modified by Steve Miller of the University of Maryland, College Park * -b sets the socket buffer size (SO_SNDBUF/SO_RCVBUF) * Modified Sept. 1989 at Silicon Graphics, Inc. * restored -s sense at request of tcs@brl * Modified Oct. 1991 at Silicon Graphics, Inc. * use getopt(3) for option processing, add -f and -T options. * SGI IRIX 3.3 and 4.0 releases don't need #define SYSV. * Modified by Douglas C. Schmidt August 10. 1993 rewrote ttcp to run atop TLI rather than sockets * Distribution Status - * Public Domain. Distribution Unlimited. */ #ifndef lint static char RCSid[] = "ttcp.c $Revision: 1.9 $"; #endif /* #define BSD43 */ /* #define BSD42 */ /* #define BSD41a */ #define SYSV /* required on SGI IRIX releases before 3.3 */ #include <stdio.h> #include <signal.h> #include <ctype.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <malloc.h> #include <string.h> #include <stdlib.h> #include <memory.h> #include <netinet/tcp.h> #include <arpa/inet.h> #include <netdb.h> #include <sys/time.h> /* struct itimerval */ #include <limits.h> #include <unistd.h> #include <fcntl.h> #include <tiuser.h> /* Set the socket options using TLI conventions... */ typedef void (*SIG_TYP)(); #if defined (__GNUC__) struct opthdr { long level; /* protocol level affected */ long name; /* option to modify */ long len; /* length of option value */ }; extern int t_errno; #endif #define SET_SO_OPTION(SOCHDR, LEVEL, OPTION, SIZE, VALUE) \ do { SOCHDR.opthdr.level = LEVEL; SOCHDR.opthdr.name = OPTION; \ SOCHDR.opthdr.len = SIZE; SOCHDR.value = VALUE; } while (0) #if defined(SYSV) #include <sys/times.h> #include <sys/param.h> struct rusage { struct timeval ru_utime, ru_stime; }; #define RUSAGE_SELF 0 #else #include <sys/resource.h> #define memcpy(A,B,C) bcopy ((A),(B),(C)) #define memset(A,B,C) bzero((A),(C)) #endif /* SYSV */ struct sockaddr_in sinme; struct sockaddr_in sinhim; struct sockaddr_in frominet; int fromlen; int fd; /* fd of network socket */ int buflen = 8 * 1024; /* length of buffer */ char *buf; /* ptr to dynamic buffer */ int nbuf = 2 * 1024; /* number of buffers to send in sinkmode */ int bufoffset = 0; /* align buffer to this */ int bufalign = 16 * 1024; /* modulo this */ int udp = 0; /* 0 = tcp, !0 = udp */ int options = 0; /* socket options */ int one = 1; /* for 4.3 BSD style setsockopt() */ short port = 5001; /* TCP port number */ char *host; /* ptr to name of host */ int trans; /* 0=receive, !0=transmit mode */ int sinkmode = 0; /* 0=normal I/O, !0=sink/source mode */ int verbose = 0; /* 0=print basic info, 1=print cpu rate, proc * resource usage. */ int nodelay = 0; /* set TCP_NODELAY socket option */ int b_flag = 0; /* use mread() */ int sockbufsize = 0; /* socket buffer size to use */ char fmt = 'K'; /* output format: k = kilobits, K = kilobytes, * m = megabits, M = megabytes, * g = gigabits, G = gigabytes */ int touchdata = 0; /* access data after reading */ struct hostent *addr; extern int errno; extern int optind; extern char *optarg; char Usage[] = "\ Usage: ttcp -t [-options] host [ < in ]\n\ ttcp -r [-options > out]\n\ Common options:\n\ -l ## length of bufs read from or written to network (default 8192)\n\ -u use UDP instead of TCP\n\ -p ## port number to send to or listen at (default 5001)\n\ -s -t: source a pattern to network\n\ -r: sink (discard) all data from network\n\ -A align the start of buffers to this modulus (default 16384)\n\ -O start buffers at this offset from the modulus (default 0)\n\ -v verbose: print more statistics\n\ -d set SO_DEBUG socket option\n\ -b ## set socket buffer size (if supported)\n\ -f X format for rate: k,K = kilo{bit,byte}; m,M = mega; g,G = giga\n\ Options specific to -t:\n\ -n## number of source bufs written to network (default 2048)\n\ -D don't buffer TCP writes (sets TCP_NODELAY socket option)\n\ Options specific to -r:\n\ -B for -s, only output full blocks as specified by -l (for TAR)\n\ -T \"touch\": access each byte as it's read\n\ "; char stats[128]; unsigned long nbytes; /* bytes on net */ unsigned long numCalls; /* # of I/O system calls */ double cput, realt; /* user, real time (seconds) */ void err (char *s); void mes (char *s); void pattern (register char *cp, register int cnt); char *outfmt (double b); static void getrusage (int ignored, register struct rusage *ru); static void gettimeofday (struct timeval *tp, struct timezone *zp); void prep_timer (void); double read_timer (char *str, int len); static void prusage (register struct rusage *r0, struct rusage *r1, struct timeval *e, struct timeval *b, char *outp); static void tvadd (struct timeval *tsum, struct timeval *t0, struct timeval *t1); static void tvsub (struct timeval *tdiff, struct timeval *t1, struct timeval *t0); static void psecs (long l, register char *cp); void delay (int us); int mread (int fd, register char *bufp, unsigned n); int Nread (int fd, char *buf, int count); int Nwrite (int fd, char *buf, int count); void sigpipe () { } /* See <sys/socket.h> for details on this format */ struct sochdr { struct opthdr opthdr; long value; } sochdr; int main (int argc, char *argv[]) { unsigned long addr_tmp; int c; struct t_optmgmt *so_options; struct t_optmgmt *so_options_ret; if (argc < 2) goto usage; while ((c = getopt (argc, argv, "drstuvBDTb:f:l:n:p:A:O:")) != -1) { switch (c) { case 'B': b_flag = 1; break; case 't': trans = 1; break; case 'r': trans = 0; break; case 'd': options |= SO_DEBUG; break; case 'D': #ifdef TCP_NODELAY nodelay = 1; #else fprintf (stderr, "ttcp: -D option ignored: TCP_NODELAY socket option not supported\n"); #endif break; case 'n': nbuf = atoi (optarg); break; case 'l': buflen = atoi (optarg); break; case 's': sinkmode = !sinkmode; break; case 'p': port = atoi (optarg); break; case 'u': udp = 1; break; case 'v': verbose = 1; break; case 'A': bufalign = atoi (optarg); break; case 'O': bufoffset = atoi (optarg); break; case 'b': #if defined(SO_SNDBUF) || defined(SO_RCVBUF) sockbufsize = atoi (optarg); #else fprintf (stderr, "ttcp: -b option ignored: SO_SNDBUF/SO_RCVBUF socket options not supported\n"); #endif break; case 'f': fmt = *optarg; break; case 'T': touchdata = 1; break; default: goto usage; } } if (trans) { /* xmitr */ if (optind == argc) goto usage; memset ((char *) &sinhim, 0, sizeof (sinhim)); host = argv[optind]; if (atoi (host) > 0) { /* Numeric */ sinhim.sin_family = AF_INET; #if defined(cray) addr_tmp = inet_addr (host); sinhim.sin_addr = addr_tmp; #else sinhim.sin_addr.s_addr = inet_addr (host); #endif } else { if ((addr = gethostbyname (host)) == NULL) err ("bad hostname"); sinhim.sin_family = addr->h_addrtype; memcpy ((char *) &addr_tmp, addr->h_addr, addr->h_length); #if defined(cray) sinhim.sin_addr = addr_tmp; #else sinhim.sin_addr.s_addr = addr_tmp; #endif /* cray */ } sinhim.sin_port = htons (port); sinme.sin_family = AF_INET; sinme.sin_port = 0; /* free choice */ } else { /* rcvr */ sinme.sin_family = AF_INET; sinme.sin_port = htons (port); sinme.sin_addr.s_addr = INADDR_ANY; } if (udp && buflen < 5) buflen = 5; /* send more than the sentinel size */ if ((buf = (char *) malloc (buflen + bufalign)) == (char *) NULL) err ("malloc"); if (bufalign != 0) buf += (bufalign - ((int) buf % bufalign) + bufoffset) % bufalign; if (trans) { fprintf (stdout, "ttcp-t: buflen=%d, nbuf=%d, align=%d/%d, port=%d", buflen, nbuf, bufalign, bufoffset, port); if (sockbufsize) fprintf (stdout, ", sockbufsize=%d", sockbufsize); fprintf (stdout, " %s -> %s\n", udp ? "udp" : "tcp", host); } else { fprintf (stdout, "ttcp-r: buflen=%d, nbuf=%d, align=%d/%d, port=%d", buflen, nbuf, bufalign, bufoffset, port); if (sockbufsize) fprintf (stdout, ", sockbufsize=%d", sockbufsize); fprintf (stdout, " %s\n", udp ? "udp" : "tcp"); } if ((fd = t_open (udp ? "/dev/udp" : "/dev/tcp", O_RDWR, 0)) < 0) err ("socket"); mes ("t_open"); if ((so_options = (struct t_optmgmt *) t_alloc (fd, T_OPTMGMT, T_ALL)) == 0) err ("t_alloc"); if ((so_options_ret = (struct t_optmgmt *) t_alloc (fd, T_OPTMGMT, T_ALL)) == 0) err ("t_alloc"); /* Set up options for TLI */ so_options->opt.maxlen = sizeof sochdr; so_options->opt.len = sizeof sochdr; so_options->opt.buf = (char *) &sochdr; so_options->flags = T_NEGOTIATE; so_options_ret->opt.maxlen = sizeof sochdr; so_options_ret->opt.len = sizeof sochdr; so_options_ret->opt.buf = (char *) &sochdr; if (!trans) /* Server side */ { struct t_bind req; req.addr.maxlen = sizeof sinme; req.addr.len = sizeof sinme; req.addr.buf = (char *) &sinme; req.qlen = 1; if (t_bind (fd, &req, 0) == -1) err ("t_bind"); } else /* Client side */ if (t_bind (fd, 0, 0) == -1) err ("t_bind"); #if defined(SO_SNDBUF) || defined(SO_RCVBUF) if (sockbufsize) { if (trans) { SET_SO_OPTION (sochdr, SOL_SOCKET, SO_SNDBUF, 4, sockbufsize); if (t_optmgmt (fd, so_options, so_options_ret) == -1) err ("t_optmgmt: sndbuf"); mes ("sndbuf"); } else { SET_SO_OPTION (sochdr, SOL_SOCKET, SO_RCVBUF, 4, sockbufsize); if (t_optmgmt (fd, so_options, so_options_ret) == -1) err ("t_optmgmt: rcvbuf"); mes ("rcvbuf"); } } #endif if (!udp) { signal (SIGPIPE, (SIG_TYP) sigpipe); if (trans) { struct t_call call; /* We are the client if transmitting */ if (options) { SET_SO_OPTION (sochdr, SOL_SOCKET, options, 4, 1); if (t_optmgmt (fd, so_options, so_options_ret) == -1) err ("t_optmgmt: debug"); } #ifdef TCP_NODELAY if (nodelay) { struct protoent *p; p = getprotobyname ("tcp"); SET_SO_OPTION (sochdr, p->p_proto, TCP_NODELAY, 4, 1); if (p && t_optmgmt (fd, so_options, so_options_ret) == -1) err ("t_optmgmt: nodelay"); mes ("nodelay"); } #endif memset (&call, 0, sizeof call); call.addr.maxlen = sizeof sinhim; call.addr.len = sizeof sinhim; call.addr.buf = (char *) &sinhim; if (t_connect (fd, &call, 0) == -1) { if (t_errno == TLOOK) printf ("t_look = %d\n", t_look (fd)); else err ("t_connect"); } mes ("t_connect"); } else { /* otherwise, we are the server and * should listen for the connections */ struct t_call *call_ptr; if ((call_ptr = (struct t_call *) t_alloc (fd, T_CALL, T_ADDR)) == 0) err ("t_alloc"); if (options) { SET_SO_OPTION (sochdr, SOL_SOCKET, options, 4, 1); if (t_optmgmt (fd, so_options, so_options_ret) == -1) err ("t_optmgmt: debug"); } if (t_listen (fd, call_ptr) == -1) err ("t_listen"); if (t_accept (fd, fd, call_ptr) == -1) err ("t_accept"); fprintf (stderr, "ttcp-r: t_accept from %s\n", inet_ntoa (((struct sockaddr_in *) call_ptr->addr.buf)->sin_addr)); } } (void) t_free ((char *) so_options, T_OPTMGMT); (void) t_free ((char *) so_options_ret, T_OPTMGMT); prep_timer (); errno = 0; if (sinkmode) { register int cnt; if (trans) { pattern (buf, buflen); if (udp) (void) Nwrite (fd, buf, 4); /* rcvr start */ while (nbuf-- && Nwrite (fd, buf, buflen) == buflen) nbytes += buflen; if (udp) (void) Nwrite (fd, buf, 4); /* rcvr end */ } else { if (udp) { while ((cnt = Nread (fd, buf, buflen)) > 0) { static int going = 0; if (cnt <= 4) { if (going) break; /* "EOF" */ going = 1; prep_timer (); } else nbytes += cnt; } } else { while ((cnt = Nread (fd, buf, buflen)) > 0) nbytes += cnt; } } } else { register int cnt; if (trans) { while ((cnt = read (0, buf, buflen)) > 0 && Nwrite (fd, buf, cnt) == cnt) nbytes += cnt; } else { while ((cnt = Nread (fd, buf, buflen)) > 0 && write (1, buf, cnt) == cnt) nbytes += cnt; } } if (errno) err ("IO"); (void) read_timer (stats, sizeof (stats)); if (udp && trans) { (void) Nwrite (fd, buf, 4); /* rcvr end */ (void) Nwrite (fd, buf, 4); /* rcvr end */ (void) Nwrite (fd, buf, 4); /* rcvr end */ (void) Nwrite (fd, buf, 4); /* rcvr end */ } if (cput <= 0.0) cput = 0.001; if (realt <= 0.0) realt = 0.001; fprintf (stdout, "ttcp%s: %ld bytes in %.2f real seconds = %s/sec +++\n", trans ? "-t" : "-r", nbytes, realt, outfmt (((double) nbytes) / realt)); if (verbose) { fprintf (stdout, "ttcp%s: %ld bytes in %.2f CPU seconds = %s/cpu sec\n", trans ? "-t" : "-r", nbytes, cput, outfmt (((double) nbytes) / cput)); } fprintf (stdout, "ttcp%s: %d I/O calls, msec/call = %.2f, calls/sec = %.2f\n", trans ? "-t" : "-r", numCalls, 1024.0 * realt / ((double) numCalls), ((double) numCalls) / realt); fprintf (stdout, "ttcp%s: %s\n", trans ? "-t" : "-r", stats); if (verbose) { fprintf (stdout, "ttcp%s: buffer address %#x\n", trans ? "-t" : "-r", buf); } exit (0); usage: fprintf (stderr, Usage); exit (1); } void err (char *s) { fprintf (stderr, "ttcp%s: ", trans ? "-t" : "-r"); t_error (s); fprintf (stderr, "errno=%d, t_errno = %d\n", errno, t_errno); exit (1); } void mes (char *s) { fprintf (stderr, "ttcp%s: %s\n", trans ? "-t" : "-r", s); } void pattern (register char *cp, register int cnt) { register char c; c = 0; while (cnt-- > 0) { while (!isprint ((c & 0x7F))) c++; *cp++ = (c++ & 0x7F); } } char * outfmt (double b) { static char obuf[50]; switch (fmt) { case 'G': sprintf (obuf, "%.2f GB", b / 1024.0 / 1024.0 / 1024.0); break; default: case 'K': sprintf (obuf, "%.2f KB", b / 1024.0); break; case 'M': sprintf (obuf, "%.2f MB", b / 1024.0 / 1024.0); break; case 'g': sprintf (obuf, "%.2f Gbit", b * 8.0 / 1024.0 / 1024.0 / 1024.0); break; case 'k': sprintf (obuf, "%.2f Kbit", b * 8.0 / 1024.0); break; case 'm': sprintf (obuf, "%.2f Mbit", b * 8.0 / 1024.0 / 1024.0); break; } return obuf; } static struct itimerval itime0; /* Time at which timing started */ static struct rusage ru0; /* Resource utilization at the start */ static void prusage (); static void tvadd (); static void tvsub (); static void psecs (); #if defined(SYSV) /*ARGSUSED*/ static void getrusage (int ignored, register struct rusage *ru) { struct tms buf; times (&buf); /* Assumption: HZ <= 2147 (LONG_MAX/1000000) */ ru->ru_stime.tv_sec = buf.tms_stime / HZ; ru->ru_stime.tv_usec = ((buf.tms_stime % HZ) * 1000000) / HZ; ru->ru_utime.tv_sec = buf.tms_utime / HZ; ru->ru_utime.tv_usec = ((buf.tms_utime % HZ) * 1000000) / HZ; } /*ARGSUSED*/ static void gettimeofday (struct timeval *tp, struct timezone *zp) { tp->tv_sec = time (0); tp->tv_usec = 0; } #endif /* SYSV */ /* * P R E P _ T I M E R * */ void prep_timer () { itime0.it_interval.tv_sec = 0; itime0.it_interval.tv_usec = 0; itime0.it_value.tv_sec = LONG_MAX / 22; /* greatest possible value , itimer() count backwards */ itime0.it_value.tv_usec = 0; getrusage (RUSAGE_SELF, &ru0); /* Init REAL Timer */ if (setitimer (ITIMER_REAL, &itime0, NULL)) { perror ("Setting 'itimer' REAL failed"); return; } } /* * R E A D _ T I M E R * */ double read_timer (char *str, int len) { struct itimerval itimedol; struct rusage ru1; struct timeval td; struct timeval tend, tstart; char line[132]; getrusage (RUSAGE_SELF, &ru1); if (getitimer (ITIMER_REAL, &itimedol)) { perror ("Getting 'itimer' REAL failed"); return (0.0); } prusage (&ru0, &ru1, &itime0.it_value, &itimedol.it_value, line); (void) strncpy (str, line, len); /* Get real time */ tvsub (&td, &itime0.it_value, &itimedol.it_value); realt = td.tv_sec + ((double) td.tv_usec) / 1000000; /* Get CPU time (user+sys) */ tvadd (&tend, &ru1.ru_utime, &ru1.ru_stime); tvadd (&tstart, &ru0.ru_utime, &ru0.ru_stime); tvsub (&td, &tend, &tstart); cput = td.tv_sec + ((double) td.tv_usec) / 1000000; if (cput < 0.00001) cput = 0.00001; return (cput); } static void prusage (register struct rusage *r0, struct rusage *r1, struct timeval *e, struct timeval *b, char *outp) { struct timeval tdiff; register time_t t; register char *cp; register int i; int ms; t = (r1->ru_utime.tv_sec - r0->ru_utime.tv_sec) * 100 + (r1->ru_utime.tv_usec - r0->ru_utime.tv_usec) / 10000 + (r1->ru_stime.tv_sec - r0->ru_stime.tv_sec) * 100 + (r1->ru_stime.tv_usec - r0->ru_stime.tv_usec) / 10000; ms = (e->tv_sec - b->tv_sec) * 100 + (e->tv_usec - b->tv_usec) / 10000; #define END(x) {while(*x) x++;} #if defined(SYSV) cp = "%Uuser %Ssys %Ereal %P"; #else #if defined(sgi) /* IRIX 3.3 will show 0 for %M,%F,%R,%C */ cp = "%Uuser %Ssys %Ereal %P %Mmaxrss %F+%Rpf %Ccsw"; #else cp = "%Uuser %Ssys %Ereal %P %Xi+%Dd %Mmaxrss %F+%Rpf %Ccsw"; #endif #endif for (; *cp; cp++) { if (*cp != '%') *outp++ = *cp; else if (cp[1]) switch (*++cp) { case 'U': tvsub (&tdiff, &r1->ru_utime, &r0->ru_utime); sprintf (outp, "%d.%01d", tdiff.tv_sec, tdiff.tv_usec / 100000); END (outp); break; case 'S': tvsub (&tdiff, &r1->ru_stime, &r0->ru_stime); sprintf (outp, "%d.%01d", tdiff.tv_sec, tdiff.tv_usec / 100000); END (outp); break; case 'E': psecs (ms / 100, outp); END (outp); break; case 'P': sprintf (outp, "%d%%", (int) (t * 100 / ((ms ? ms : 1)))); END (outp); break; #if !defined(SYSV) case 'W': i = r1->ru_nswap - r0->ru_nswap; sprintf (outp, "%d", i); END (outp); break; case 'X': sprintf (outp, "%d", t == 0 ? 0 : (r1->ru_ixrss - r0->ru_ixrss) / t); END (outp); break; case 'D': sprintf (outp, "%d", t == 0 ? 0 : (r1->ru_idrss + r1->ru_isrss - (r0->ru_idrss + r0->ru_isrss)) / t); END (outp); break; case 'K': sprintf (outp, "%d", t == 0 ? 0 : ((r1->ru_ixrss + r1->ru_isrss + r1->ru_idrss) - (r0->ru_ixrss + r0->ru_idrss + r0->ru_isrss)) / t); END (outp); break; case 'M': sprintf (outp, "%d", r1->ru_maxrss / 2); END (outp); break; case 'F': sprintf (outp, "%d", r1->ru_majflt - r0->ru_majflt); END (outp); break; case 'R': sprintf (outp, "%d", r1->ru_minflt - r0->ru_minflt); END (outp); break; case 'I': sprintf (outp, "%d", r1->ru_inblock - r0->ru_inblock); END (outp); break; case 'O': sprintf (outp, "%d", r1->ru_oublock - r0->ru_oublock); END (outp); break; case 'C': sprintf (outp, "%d+%d", r1->ru_nvcsw - r0->ru_nvcsw, r1->ru_nivcsw - r0->ru_nivcsw); END (outp); break; #endif /* !SYSV */ } } *outp = '\0'; } static void tvadd (struct timeval *tsum, struct timeval *t0, struct timeval *t1) { tsum->tv_sec = t0->tv_sec + t1->tv_sec; tsum->tv_usec = t0->tv_usec + t1->tv_usec; if (tsum->tv_usec > 1000000) tsum->tv_sec++, tsum->tv_usec -= 1000000; } static void tvsub (struct timeval *tdiff, struct timeval *t1, struct timeval *t0) { tdiff->tv_sec = t1->tv_sec - t0->tv_sec; tdiff->tv_usec = t1->tv_usec - t0->tv_usec; if (tdiff->tv_usec < 0) tdiff->tv_sec--, tdiff->tv_usec += 1000000; } static void psecs (long l, register char *cp) { register int i; i = l / 3600; if (i) { sprintf (cp, "%d:", i); END (cp); i = l % 3600; sprintf (cp, "%d%d", (i / 60) / 10, (i / 60) % 10); END (cp); } else { i = l; sprintf (cp, "%d", i / 60); END (cp); } i %= 60; *cp++ = ':'; sprintf (cp, "%d%d", i / 10, i % 10); } /* * N R E A D */ int Nread (int fd, char *buf, int count) { register int cnt; int flags = 0; if (udp) { struct sockaddr_in from; struct t_unitdata udata; udata.addr.maxlen = sizeof from; udata.addr.buf = (char *) &from; udata.udata.maxlen = count; udata.udata.buf = (char *) buf; cnt = t_rcvudata (fd, &udata, &flags); if (cnt != -1) cnt = udata.udata.len; numCalls++; } else { if (b_flag) cnt = mread (fd, buf, count); /* fill buf */ else { cnt = t_rcv (fd, buf, count, &flags); numCalls++; } if (touchdata && cnt > 0) { register int c = cnt, sum; register char *b = buf; while (c--) sum += *b++; } } return (cnt); } /* * N W R I T E */ int Nwrite (int fd, char *buf, int count) { register int cnt; if (udp) { struct t_unitdata udata; memset (&udata, 0, sizeof udata); udata.addr.len = sizeof sinhim; udata.addr.buf = (char *) &sinhim; udata.udata.len = count; udata.udata.buf = (char *) buf; again: cnt = t_sndudata (fd, &udata); numCalls++; if (cnt == -1) { if (errno == ENOBUFS) { delay (18000); errno = 0; goto again; } else err ("t_sndudata"); } else cnt = udata.udata.len; } else { cnt = t_snd (fd, buf, count, 0); numCalls++; } return (cnt); } void delay (int us) { struct timeval tv; tv.tv_sec = 0; tv.tv_usec = us; (void) select (1, (fd_set *) 0, (fd_set *) 0, (fd_set *) 0, &tv); } /* * M R E A D * * This function performs the function of a read(II) but will * call read(II) multiple times in order to get the requested * number of characters. This can be necessary because * network connections don't deliver data with the same * grouping as it is written with. Written by Robert S. Miles, BRL. */ int mread (int fd, register char *bufp, unsigned n) { register unsigned count = 0; register int nread; int flags = 0; do { nread = t_rcv (fd, bufp, n - count, &flags); numCalls++; if (nread < 0) { perror ("ttcp_mread"); return (-1); } if (nread == 0) return ((int) count); count += (unsigned) nread; bufp += nread; } while (count < n); return ((int) count); } /* int proc; char buf[100]; prusage_t r; (void)sprintf(buf, "/proc/%d", getpid()); if ((proc = open(buf, O_RDONLY, 0)) < 0) { fprintf(stderr, "open('%s'):", buf); perror(""); } else if (ioctl(proc, PIOCUSAGE, (void *)&r) < 0) perror("ioctl(PIOCUSAGE)"); */ -- Dr. Douglas C. Schmidt (schmidt@cs.wustl.edu) Department of Computer Science, Washington University St. Louis, MO 63130. Work #: (314) 935-7538; FAX #: (314) 035-7302 http://www.cs.wustl.edu/~schmidt