allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (11/13/89)
Posting-number: Volume 9, Issue 4 Submitted-by: gene@digibd (Gene H. Olson) Archive-name: tbench This is a set of benchmark programs to test the performance of UNIX tty subsystems under load. It was developed by a vendor of multi-port communication boards; there may be some bias. #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: README cpu.c ibench iprint islave obench oprint perf.c # Wrapped by gene@digibd on Sun Nov 12 18:29:48 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f README -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"README\" else echo shar: Extracting \"README\" \(23749 characters\) sed "s/^X//" >README <<'END_OF_README' X#################################################### X# This software released to the public domain # X# without restrictions of any kind. # X#################################################### X X @(#)README 3.4 11/12/89 X XThe programs included in this, the first release of TBENCH Xwere all developed by DigiBoard Incorporated (St. Louis Pk, MN) Xfor internal performance testing. DigiBoard used these to Xtest their own, and competitors multiport communication Xboards. Some of those results have been published in trade Xmagazines. X XThese benchmarks are a another attempt at developing objective Xbenchmarks to compare the performance of tty subsystems under Xextreme load. An earlier benchmark suite developed by ANVIL X(Australia) was posted to comp.sys.i386 some time ago. Those Xwere a fine first attempt, but did suffer from some limitations. X XAt DigiBoard, we believe these benchmarks provide a much Xbetter indication of steady state tty I/O performance. XIn particular they send data for a length of time before Xbenchmarking begins, and after it completes, so that the Xresults are closer to indicating steady-state performance. XThey also check input data automatically, and provide a Xsummary of the errors detected. X XDigiBoard has made an attempt to keep these benchmarks as Xobjective as possible. However DigiBoard is a for-profit Xcompany, and as such must have included some bias. Anyone Xusing these benchmarks is heartily encouraged to analyze Xthem, improve them, and if they see fit, to criticize them Xas needed. X XThese programs have been tested on essentially all UNIX Xports to 286/386 PC-compatible systems, and also on Suns. X XSend bug fixes, enhancements, comments (and flames) to: X XGene H. Olson uunet!digibd!gene XMember of Technical Staff XDigiBoard Inc. XSt. Louis Park, MN (612) 922-8055 X X------------------------------------------------------------ X XThe remainder of this file describes how to use the terminal Xbenchmark programs. We assume the reader is an experienced XUNIX user, thoroughly familiar with the concept of tty devices Xand modes, and very comfortable at the UNIX command level. XNovice UNIX users may find these notes incomprehensible. X X XTHE PROGRAMS X------------ X XBefore you can use these benchmarks, you need to compile two Xprograms, and run one of them to calibrate it for use on your Xsystem. Enter the following commands: X X cc -o perf -O perf.c X cc -o cpu cpu.c X ./cpu -c X XWhen compiling perf.c and cpu.c you are wise to make sure your Xsystem is using setvbuf() with the correct parameter sequence. XThe original UNIX 5.2 release had parameters 2 and 3 reversed Xfrom the setbuf(3) manual page, and from subsequent releases of XUNIX. However while the manual pages were different, the lint(1) Xlibrary file was consistent with the way the parameters were Xactually used. I suggest you run lint on these programs before Xattempting to use them. If you get an error on the setvbuf() Xdeclaration, then use instead: X X cc -DSETVBUF -o perf -O perf.c X cc -DSETVBUF -o cpu cpu.c X ./cpu -c X XThe programs now available include: X Xperf C program which may be invoked for either input or X output testing. X X In output mode, the program writes 6 digit numbers X (plus checksum) to standard output, which should be X redirected to the tty under test. The program reports X the output speed, real (elapsed) time, and system X time consumed. X X In input mode, perf reads the output of another perf X in output mode, redirected through a pair of tty ports. X The program compares the actual data received to the X expected input and reports error statistics. The X report includes the speed of input, real time, system X time, the number of codes missing or in error, and X the number of stray characters received. X X Xcpu C program to determine how busy the system is during X input/output testing. X X This program must first be run on an idle system to X calibrate its internal loop. Thereafter it may be X invoked to drop its priority and absorb all available X idle time. Using a combination of reported system time X and its own internally calibrated loop, it displays X the amount of CPU time consumed elsewhere at both X process and interrupt levels. X X The assignment of time to process and interrupt levels X is very approximate, but the total is an accurate X reflection of the CPU being utilized by other programs. X If the only other programs running are the terminal X benchmarks, the results are quite good. X X If your system contains memory of different speeds, X this program may report grossly inaccurate results. X There is no solution, except to change memory boards X or move to another system. X X Xobench A shell file to supervise output testing. X X The program takes as parameters a list of ttys, X test modes and baud rates. It runs the perf program X on 1 to n of these terminals in all of the mode and X baud rate combinations given. The results of these X tests are written to standard output, and should be X captured to a file. X X Xoprint A shell file to summarize the results reported by X the obench shell file above. X X Xislave A shell file to monitor input terminals and report X the speed and accuracy of the input actually received. X X This program takes as parameters a baud rate, X and a list of terminals to be monitored. The X data coming into the terminals may include test X commands and data supplied by the ibench program X below. The results are written to standard output, X and should be captured to a file. X X Xibench A shell file to supervise input testing and to produce X test data for by the islave program above. X X Ibench takes as parameters a list of ttys, test modes, X and baud rates. It runs the perf program to write X test commands and data to the given ttys. These X ttys are then connected to terminals monitored by the X islave program above. X X The commands sent out by ibench cause the islave program X to print messages, change input modes and baud rates X as the test progresses. X X Xiprint A shell file to summarize the results reported by X the islave shell file above. X X X XOUTPUT TEST PROCEDURE X--------------------- X XOutput testing is straightforward, and requires minimal hardware Xsetup. X XThe benchmark writes data out to multiple ports as fast as possible, Xwithout flow control, so it is not necessary to hookup the cables to Xterminals. X XTo perform the test on a DigiBoard PC/8e under SCO Xenix, type Xthe following command on the system console: X X obench 9600 exta extb opost -opost /dev/ttyi1[a-h] | tee junk X XThis command outputs data at baud rates 9600, exta (19200), Xand extb (38400) to the given ports in both opost (cooked) and X-opost (raw) modes. All combinations of baud rates and modes Xare tested, using 1-8 terminals each. This yields a total of 3 baud Xrates * 2 modes * 8 terminals = 48 different tests, each writing Xabout 100K characters to 1 or more terminals. X XIf all goes well, the test takes about 2 hours. The test output Xis displayed on the terminal and written to the file junk. The Xoutput should look similar to: X XTEST tty=1, baud=9600, mode=opost XTIME process=5.7, interrupt=-0.1, total=5.6 X/dev/ttyi1a : OUT cps=965, real=103.58, user=0.4, sys=5.1 XTEST tty=2, baud=9600, mode=opost XTIME process=11.3, interrupt=-0.1, total=11.2 X/dev/ttyi1b : OUT cps=965, real=103.54, user=0.5, sys=5.1 X/dev/ttyi1a : OUT cps=965, real=103.54, user=0.4, sys=4.9 XTEST tty=3, baud=9600, mode=opost XTIME process=16.1, interrupt=0.5, total=16.6 X/dev/ttyi1b : OUT cps=965, real=103.58, user=0.4, sys=5.0 X/dev/ttyi1c : OUT cps=965, real=103.56, user=0.5, sys=5.2 X/dev/ttyi1a : OUT cps=965, real=103.56, user=0.3, sys=5.0 XTEST tty=4, baud=9600, mode=opost XTIME process=21.7, interrupt=0.7, total=22.3 X/dev/ttyi1b : OUT cps=965, real=103.56, user=0.4, sys=5.1 X/dev/ttyi1c : OUT cps=965, real=103.56, user=0.6, sys=5.0 X/dev/ttyi1d : OUT cps=965, real=103.62, user=0.4, sys=5.0 X/dev/ttyi1a : OUT cps=965, real=103.62, user=0.4, sys=5.0 XTEST tty=5, baud=9600, mode=opost XTIME process=28.3, interrupt=-0.3, total=27.9 X/dev/ttyi1b : OUT cps=965, real=103.60, user=0.6, sys=5.1 X/dev/ttyi1d : OUT cps=965, real=103.56, user=0.4, sys=5.0 X/dev/ttyi1e : OUT cps=965, real=103.56, user=0.6, sys=5.1 X/dev/ttyi1a : OUT cps=965, real=103.60, user=0.5, sys=5.1 X/dev/ttyi1c : OUT cps=963, real=103.82, user=0.6, sys=4.8 XTEST tty=6, baud=9600, mode=opost XTIME process=32.4, interrupt=1.0, total=33.5 X/dev/ttyi1c : OUT cps=964, real=103.64, user=0.5, sys=4.8 X/dev/ttyi1f : OUT cps=965, real=103.56, user=0.6, sys=5.1 X/dev/ttyi1a : OUT cps=965, real=103.60, user=0.4, sys=5.0 X/dev/ttyi1e : OUT cps=965, real=103.56, user=0.4, sys=5.2 X/dev/ttyi1b : OUT cps=965, real=103.56, user=0.5, sys=4.8 X/dev/ttyi1d : OUT cps=965, real=103.56, user=0.6, sys=4.9 XTEST tty=7, baud=9600, mode=opost XTIME process=36.8, interrupt=3.1, total=39.9 X/dev/ttyi1d : OUT cps=965, real=103.62, user=0.4, sys=5.1 X/dev/ttyi1f : OUT cps=964, real=103.70, user=0.4, sys=5.1 X/dev/ttyi1b : OUT cps=957, real=104.48, user=0.5, sys=4.9 X/dev/ttyi1g : OUT cps=964, real=103.72, user=0.4, sys=4.9 X/dev/ttyi1c : OUT cps=962, real=103.94, user=0.4, sys=5.0 X/dev/ttyi1a : OUT cps=964, real=103.64, user=0.5, sys=4.9 X/dev/ttyi1e : OUT cps=958, real=104.34, user=0.7, sys=5.0 XTEST tty=8, baud=9600, mode=opost XTIME process=45.0, interrupt=0.5, total=45.5 X/dev/ttyi1a : OUT cps=961, real=103.96, user=0.6, sys=4.9 X/dev/ttyi1d : OUT cps=963, real=103.78, user=0.6, sys=5.1 X/dev/ttyi1f : OUT cps=964, real=103.66, user=0.5, sys=5.1 X/dev/ttyi1c : OUT cps=963, real=103.74, user=0.6, sys=5.1 X/dev/ttyi1h : OUT cps=957, real=104.46, user=0.5, sys=5.1 X/dev/ttyi1b : OUT cps=955, real=104.70, user=0.4, sys=4.8 X/dev/ttyi1g : OUT cps=963, real=103.80, user=0.4, sys=5.1 X/dev/ttyi1e : OUT cps=964, real=103.68, user=0.6, sys=5.0 XTEST tty=1, baud=9600, mode=-opost XTIME process=1.6, interrupt=0.0, total=1.6 X/dev/ttyi1a : OUT cps=960, real=104.16, user=0.5, sys=1.1 XTEST tty=2, baud=9600, mode=-opost XTIME process=2.9, interrupt=0.2, total=3.1 X/dev/ttyi1b : OUT cps=959, real=104.18, user=0.5, sys=0.9 X/dev/ttyi1a : OUT cps=960, real=104.14, user=0.4, sys=0.9 XTEST tty=3, baud=9600, mode=-opost X ... X XWhen the test is complete, you may summarize the data in tabular Xform by typing: X X oprint junk X XThis prints a summary of the input received in tabular format with Xcolumn headers. The output should resemble: X X ports baud mode cps real %sys %host X ----- ------ ------ ----- ------ ----- ---- X 1 9600 opost 965.0 103.6 5.1 5.31 X 2 9600 opost 965.0 103.5 10.2 5.31 X 3 9600 opost 965.0 103.6 15.2 5.24 X 4 9600 opost 965.0 103.6 20.4 5.28 X 5 9600 opost 964.6 103.6 25.5 5.29 X 6 9600 opost 964.8 103.6 30.6 5.29 X 7 9600 opost 962.0 103.9 36.6 5.43 X 8 9600 opost 961.3 104.0 41.7 5.42 X X 1 9600 -opost 960.0 104.2 1.1 1.17 X 2 9600 -opost 959.5 104.2 2.2 1.12 X 3 9600 -opost 959.0 104.2 3.2 1.11 X 4 9600 -opost 959.5 104.2 4.3 1.12 X 5 9600 -opost 958.8 104.2 5.3 1.11 X 6 9600 -opost 959.7 104.2 6.4 1.10 X 7 9600 -opost 958.6 104.2 8.7 1.29 X 8 9600 -opost 958.6 104.2 9.7 1.27 X X 1 19200 opost 1919.0 104.2 10.2 5.29 X 2 19200 opost 1922.0 104.0 20.4 5.31 X 3 19200 opost 1921.7 104.0 30.5 5.28 X 4 19200 opost 1920.8 104.1 40.6 5.29 X 5 19200 opost 1920.4 104.1 50.8 5.29 X 6 19200 opost 1920.2 104.1 61.0 5.30 X 7 19200 opost 1919.6 104.2 71.5 5.32 X 8 19200 opost 1917.4 104.3 81.3 5.30 X X 1 19200 -opost 1921.0 104.1 2.1 1.07 X ... X X XThe columns printed are: X Xbaud The test baud rate. X Xmode The communication mode, either opost (cooked) or -opost X (raw). X Xflow The flow control mode, either ixon (output flow control) X -ixon (no flow control). X Xcps The character per second (cps) output speed actually measured. X Under ideal conditions, this will be the baud rate divided X by 10. Lower numbers indicate a reduction in performance. X X%sys Percent of system time used during the steady-state portion of X the test. This is computed by starting with 100%, subtracting X the "perf" program user time, and the idle time measured by X the "cpu" program. Because it is a subtractive method, it X is less accurate at lower loads, and progressively more X accurate as the load increases. X X%host Percent of system time used per kilo-character of output. X X XINPUT TEST PROCEDURE X-------------------- X XInput testing is much harder than output testing. To do a good job, Xyou need two systems, the system being tested, and another system Xto produce the test data. You must cable the two systems together, Xand run programs on both systems. In all, it is about 3 times as Xmuch work as the output test procedure. X XFor reference, call the system producing the test data the "producer", Xand the system under test the "consumer". If you wish to test Xinput on 8 lines simultaneously, you must cable 8 ports on the Xproducer to 8 ports on the consumer system. You will probably need Xa gender changer and a null modem connector for each line as well. X XMost intelligent cards will do output much faster than they do input, Xso generally the consumer system will overload before the producer Xsystem begins to slow down. This is not always true however, so Xyou should make sure your results do not suffer because the producer Xsystem cannot run full speed. X XI suggest you check out the lines with "cu" before you start testing Xto make sure everything really works. I can tell you from experience Xit is frustrating to discover a bad line when the input test is X3/4 complete. X XWith a DigiBoard PC/8e under SCO Xenix, begin the test by typing the Xfollowing command on the console of the consumer system: X X islave 9600 /dev/ttyi1[a-h] | tee junk X XThen go to the console of the producer system and type: X X ibench 9600 exta extb ixoff -icanon /dev/ttyi1[a-h] X XThe producer system will begin sending commands and test data to Xthe consumer system; the consumer system will report test results Xon the console and in the file "junk". X XSince the producer system sends commands as well as test data to Xthe consumer system, it is essential that communication between the Xtwo systems remains intact during the test. Remember that you may Xbe seriously overloading the input capacity of the consumer system, Xcausing test commands to be lost. If this phenomenon occurs, it Xmay be necessary to run the tests by hand. X XYou should check the output on the consoles of both the producer Xand consumer systems as the test progresses. The same number of Xdisplay lines are written to both terminals in a very similar format, Xso it is easy to see if there is a problem. X XThe output written to the consumer display, and captured in the Xfile junk should be very similar to the following: X XTEST tty=1, baud=9600, mode=-icanon, flow=ixoff XTIME process=0.0, interrupt=6.5, total=6.5 X/dev/ttyi1a : IN cps=960, real=104.16, user=0.0, sys=0.0, errs=0, stray=0 XTEST tty=2, baud=9600, mode=-icanon, flow=ixoff XTIME process=0.0, interrupt=12.4, total=12.4 X/dev/ttyi1e : IN cps=960, real=104.16, user=0.0, sys=0.0, errs=0, stray=0 X/dev/ttyi1a : IN cps=960, real=104.16, user=0.0, sys=0.0, errs=0, stray=0 XTEST tty=3, baud=9600, mode=-icanon, flow=ixoff XTIME process=0.0, interrupt=16.7, total=16.8 X/dev/ttyi1b : IN cps=960, real=104.16, user=0.0, sys=0.0, errs=0, stray=0 X/dev/ttyi1a : IN cps=959, real=104.20, user=0.0, sys=0.0, errs=0, stray=0 X/dev/ttyi1e : IN cps=960, real=104.16, user=0.0, sys=0.0, errs=0, stray=0 XTEST tty=4, baud=9600, mode=-icanon, flow=ixoff XTIME process=0.0, interrupt=21.7, total=21.7 X/dev/ttyi1e : IN cps=960, real=104.14, user=0.0, sys=0.0, errs=0, stray=0 X/dev/ttyi1b : IN cps=959, real=104.18, user=0.0, sys=0.0, errs=0, stray=0 X/dev/ttyi1f : IN cps=960, real=104.14, user=0.0, sys=0.0, errs=0, stray=0 X/dev/ttyi1a : IN cps=959, real=104.18, user=0.0, sys=0.0, errs=0, stray=0 XTEST tty=5, baud=9600, mode=-icanon, flow=ixoff XTIME process=0.1, interrupt=26.5, total=26.6 X/dev/ttyi1a : IN cps=959, real=104.18, user=0.0, sys=0.0, errs=0, stray=0 X/dev/ttyi1f : IN cps=960, real=104.14, user=0.0, sys=0.0, errs=0, stray=0 X/dev/ttyi1e : IN cps=960, real=104.14, user=0.0, sys=0.0, errs=0, stray=0 X/dev/ttyi1b : IN cps=960, real=104.14, user=0.0, sys=0.0, errs=0, stray=0 X/dev/ttyi1c : IN cps=959, real=104.18, user=0.0, sys=0.0, errs=0, stray=0 XTEST tty=6, baud=9600, mode=-icanon, flow=ixoff XTIME process=0.0, interrupt=31.2, total=31.2 X/dev/ttyi1e : IN cps=960, real=104.16, user=0.0, sys=0.0, errs=0, stray=0 X/dev/ttyi1b : IN cps=960, real=104.16, user=0.0, sys=0.0, errs=0, stray=0 X/dev/ttyi1f : IN cps=960, real=104.16, user=0.0, sys=0.0, errs=0, stray=0 X/dev/ttyi1a : IN cps=960, real=104.16, user=0.0, sys=0.0, errs=0, stray=0 X/dev/ttyi1c : IN cps=960, real=104.16, user=0.0, sys=0.0, errs=0, stray=0 X/dev/ttyi1g : IN cps=960, real=104.16, user=0.0, sys=0.0, errs=0, stray=0 XTEST tty=7, baud=9600, mode=-icanon, flow=ixoff XTIME process=0.1, interrupt=36.1, total=36.1 X/dev/ttyi1b : IN cps=960, real=104.16, user=0.0, sys=0.0, errs=0, stray=0 X/dev/ttyi1f : IN cps=960, real=104.16, user=0.0, sys=0.0, errs=0, stray=0 X/dev/ttyi1e : IN cps=959, real=104.18, user=0.0, sys=0.0, errs=0, stray=0 X/dev/ttyi1a : IN cps=960, real=104.14, user=0.0, sys=0.0, errs=0, stray=0 X/dev/ttyi1c : IN cps=960, real=104.14, user=0.0, sys=0.0, errs=0, stray=0 X/dev/ttyi1g : IN cps=960, real=104.14, user=0.0, sys=0.0, errs=0, stray=0 X/dev/ttyi1d : IN cps=960, real=104.14, user=0.0, sys=0.0, errs=0, stray=0 XTEST tty=8, baud=9600, mode=-icanon, flow=ixoff XTIME process=0.2, interrupt=40.1, total=40.3 X/dev/ttyi1b : IN cps=956, real=104.52, user=0.0, sys=0.0, errs=0, stray=0 X/dev/ttyi1a : IN cps=956, real=104.52, user=0.0, sys=0.0, errs=0, stray=0 X/dev/ttyi1f : IN cps=956, real=104.56, user=0.0, sys=0.0, errs=0, stray=0 X/dev/ttyi1e : IN cps=956, real=104.52, user=0.0, sys=0.0, errs=0, stray=0 X/dev/ttyi1d : IN cps=956, real=104.52, user=0.0, sys=0.0, errs=0, stray=0 X/dev/ttyi1c : IN cps=956, real=104.52, user=0.0, sys=0.0, errs=0, stray=0 X/dev/ttyi1g : IN cps=956, real=104.60, user=0.0, sys=0.1, errs=0, stray=0 X/dev/ttyi1h : IN cps=956, real=104.60, user=0.0, sys=0.0, errs=0, stray=0 XTEST tty=1, baud=9600, mode=icanon, flow=ixoff XTIME process=0.0, interrupt=13.4, total=13.4 X/dev/ttyi1a : IN cps=960, real=104.14, user=0.0, sys=0.0, errs=0, stray=0 XTEST tty=2, baud=9600, mode=icanon, flow=ixoff XTIME process=0.0, interrupt=24.4, total=24.5 X/dev/ttyi1e : IN cps=960, real=104.16, user=0.0, sys=0.0, errs=0, stray=0 X/dev/ttyi1a : IN cps=960, real=104.16, user=0.0, sys=0.0, errs=0, stray=0 XTEST tty=3, baud=9600, mode=icanon, flow=ixoff XTIME process=12.6, interrupt=22.6, total=35.2 X ... X XNote that both the "errs" and "stray" counts should ideally be zero Xduring this test until the consumer system becomes overloaded. XEach system is different, but it is usually easy to see when things Xare beginning to go wrong. X XWhen the test is complete, you should then run iprint to format Xthe input results you got above. Type the following command on Xthe consumer system: X X iprint junk X XThis action will produce a report similar to the following: X X ports baud mode flow cps errs %sys %host X ----- ------ ------ ------ ----- ------ ------- ------ X X 1 19200 -icanon ixoff 1920.0 0.0 8.51 4.43 X 2 19200 -icanon ixoff 1913.0 0.0 14.03 3.67 X 3 19200 -icanon ixoff 1919.0 0.0 20.44 3.55 X 4 19200 -icanon ixoff 1919.3 0.0 26.65 3.47 X 5 19200 -icanon ixoff 1919.8 0.0 33.17 3.46 X 6 19200 -icanon ixoff 1919.5 0.0 38.88 3.38 X 7 19200 -icanon ixoff 1919.4 0.0 44.79 3.33 X 8 19200 -icanon ixoff 1919.1 0.0 49.69 3.37 X 9 19200 -icanon ixoff 1919.6 0.0 57.42 3.32 X 10 19200 -icanon ixoff 1919.2 0.0 63.54 3.31 X 11 19200 -icanon ixoff 1919.6 0.0 69.85 3.31 X 12 19200 -icanon ixoff 1919.0 0.0 75.96 3.30 X 13 19200 -icanon ixoff 1919.5 0.0 81.57 3.27 X 14 19200 -icanon ixoff 1918.3 0.0 83.60 3.11 X 15 19200 -icanon ixoff 1872.4 0.0 83.60 2.98 X 16 19200 -icanon ixoff 1828.6 0.0 83.24 2.84 X X 1 38400 -icanon ixoff 3839.0 0.0 12.03 3.13 X 2 38400 -icanon ixoff 3840.0 0.0 21.45 2.79 X 3 38400 -icanon ixoff 3839.7 0.0 31.28 2.72 X 4 38400 -icanon ixoff 3838.8 0.0 41.11 2.68 X 5 38400 -icanon ixoff 3839.6 0.0 50.43 2.63 X ... X XThe columns printed are: X Xbaud The test baud rate. X Xmode The communication mode, either icanon (cooked) or -icanon X (raw). X Xflow The flow control mode, either ixoff (input flow control) X -ixoff (no flow control). X Xcps The character per second (cps) input speed actually measured. X Under ideal conditions, this will be the baud rate divided X by 10. Lower numbers indicate a reduction in performance. X Higher numbers indicate the consumer system clock is running X slow during the test; check with a stopwatch. X Xerrors Number of 6 digit + checksum codes missing from the input X stream. When this number goes non-zero, you may assume you X have begun to overload the producer system. X X%sys Percent of system time used during the steady-state portion of X the test. This is computed by starting with 100%, subtracting X the "perf" program user time, and the idle time measured by X the "cpu" program. Because it is a subtractive method, it X is less accurate at lower loads, and progressively more X accurate as the load increases. X X%host Percent of system time used per kilo-character of input X data received. X XIf there are any obvious inconsistencies in the input, iprint will Xinsert an error line to let you know. You may wish to just edit out Xthe input data in error, and replace it with corresponding comment Xlines explaining the problem. X XIf you wish, you may edit comment lines into your raw data files Xto identify details of the test, and problems you encountered. XSuch comments lines must contain a pound sign (#) in column 1. XComments are passed transparently through both oprint and iprint. END_OF_README if test 23749 -ne `wc -c <README`; then echo shar: \"README\" unpacked with wrong size! fi # end of overwriting check fi if test -f cpu.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"cpu.c\" else echo shar: Extracting \"cpu.c\" \(7481 characters\) sed "s/^X//" >cpu.c <<'END_OF_cpu.c' X/* :ex:se ts=4 sw=4 This program formatted with tabs 4 */ X X/**************************************************** X * This software released to the public domain * X * without restrictions of any kind. * X ****************************************************/ X X/* X * NAME X * cpu - CPU activity sensor X * X * SYNOPSIS X * cpu [ -cdr ] [-s delay ] [ -t time ] X * X * DESCRIPTION X * CPU is a program to detect the overall processor X * activity present in a system as part of performance X * testing. CPU must be calibrated on an idle X * system, where it times a test loop and writes X * the results to the file /tmp/.cpu. Thereafter X * CPU may be run at any time when the system is X * under load. Using CPU statistics provided by X * the system, and by measuring the test loop slowdown, X * the program can approximate general system CPU loading. X * X * -c Calibrate. Should be run when the system X * is as idle as possible; single user mode X * is best. X * X * -d Turn on debugging flags. X * X * -r Test repeatedly until interrupted. X * X * -s delay Sleep for the given delay time before X * beginning the test. X * X * -t time Run the test for time seconds. X * X * On completion, CPU outputs the following 3 time values. X * X * process The amount of time the system reported X * that other processes were running. X * X * interrupt The slowdown of the test loop not reflected X * by the system statistics. Most likely this X * time was consumed by interrupt routines, by X * task switching overhead, or because activity X * was synchronized to the system clock. X * X * total The total slowdown of the test loop relative X * to the speed measured at calibration time. X * X * The total time is the most interesting, since it reflects X * the real processor utilization abosorbed by other processes. X * Proper use of the other two numbers is left as a problem X * for the reader. X * X * WARNINGS X * CPU is astoundingly inaccurate in systems with different X * speed memories. In some systems (eg i386 with 16 bit X * memory on the AT bus) it is not uncommon for calibration X * runs to vary by a factor of 2 or more. There is no X * solution but to change the memory or find another machine. X * X * The order of parameters 2 & 3 on setvbuf() vary from X * system, and are even inconsistent between the manuals X * and the libraries on stock system V.2. You are wise X * to check the order of the parameters on your system and X * set the SETVBUF #define accordingly. X */ X X#if !defined(lint) Xchar whatstring[] = "@(#)cpu.c 3.1 9/22/89" ; X#endif X X#if sun X#define BSD 1 X#endif X X#if BSD X# include <sys/types.h> X# include <sys/time.h> X# include <sys/resource.h> X#else X# include <sys/types.h> X# include <sys/times.h> X# include <sys/param.h> X#endif X X#include <signal.h> X#include <ctype.h> X#include <stdio.h> X X#define uchar unsigned char X#define ushort unsigned short X#define ulong unsigned long X Xextern char *optarg ; Xextern int optind ; X Xextern char *ttyname() ; Xextern long atol() ; Xextern void (*signal())() ; Xextern unsigned sleep() ; X X#if BSD X#else Xextern unsigned alarm() ; Xextern void exit() ; Xextern void perror() ; Xextern time_t times() ; X#endif X X X#if BSD X# define TICS 1000 /* Fractional seconds */ X# define MS(tv) (1000000L / TICS * (tv).tv_sec + (tv).tv_usec / TICS) X#else X# define TICS HZ X#endif X X#define CALFILE "/tmp/.cpu" X X Xdouble speed ; /* Speed of the processor running */ Xdouble process ; /* Amount of the machine allocated to us */ X Xint debug ; /* Debug flag */ Xint delay ; /* Delay before start */ Xint timeout ; /* Alarm occurred flag */ Xint interrupt ; /* Got an interrupt */ X Xulong rep ; /* Repeat count */ X X X X/******* X * Catch interrupts. X */ X Xsigalrm() X{ X timeout = 1 ; X} X Xsigint() X{ X interrupt = 1 ; X} X X X/******* X * delay - Routine to chew time. X */ X Xhog() X{ X static int a = 1 ; X static int b = 2 ; X static int c = 3 ; X X a += b ; X b += c ; X c += a ; X} X X X/******* X * measure - Procedure to measure our access to the CPU. X */ X Xmeasure(runtime) Xint runtime ; /* Time period */ X{ X ulong real ; X ulong sys ; X ulong user ; X ulong count ; X X#if BSD X struct timeval tv ; X struct rusage ru ; X#else X struct tms tms ; X#endif X X /* X * Get real time and system time. X */ X X#if BSD X (void) gettimeofday(&tv, (struct timezone *)0) ; X real = MS(tv) ; X X (void) getrusage(RUSAGE_SELF, &ru) ; X user = MS(ru.ru_utime) ; X sys = MS(ru.ru_stime) ; X#else X real = times(&tms) ; X user = tms.tms_utime ; X sys = tms.tms_stime ; X#endif X X if (debug) (void) fprintf(stderr,"Cpu started\n") ; X X timeout = 0 ; X count = 0 ; X X (void) signal(SIGALRM, sigalrm) ; X (void) alarm((unsigned) runtime) ; X X (void) nice(40) ; X X while (!timeout && !interrupt) X { X hog() ; X count++ ; X } X X (void) nice(-40) ; X X#if BSD X (void) gettimeofday(&tv, (struct timezone *)0) ; X real = MS(tv) - real ; X X (void) getrusage(RUSAGE_SELF, &ru) ; X user = MS(ru.ru_utime) - user ; X sys = MS(ru.ru_stime) - sys ; X#else X real = times(&tms) - real ; X user = tms.tms_utime - user ; X sys = tms.tms_stime - sys ; X#endif X X process = (double) user / (double) real ; X speed = user ? (double) count / (double) user : 0.0 ; X X if (debug) X { X (void) fprintf(stderr, X "real=%ld, sys=%ld, user=%ld, count=%ld\n", X real, sys, user, count) ; X (void) fprintf(stderr, "raw process=%.5f, speed=%.5f\n", X process, speed) ; X } X} X X X Xmain(argc, argv) Xint argc ; Xchar **argv ; X{ X double cprocess ; X double cspeed ; X int calibrate ; X int runtime = 30 ; X int err ; X int c ; X FILE *cfile ; X char iobuf[1024] ; X char buf[200] ; X X#if SETVBUF X (void) setvbuf(stderr, _IOLBF, iobuf, sizeof(iobuf)) ; X#else X (void) setvbuf(stderr, iobuf, _IOLBF, sizeof(iobuf)) ; X#endif X X (void) nice(-40) ; X X calibrate = 0 ; X err = 0 ; X X while ((c = getopt(argc, argv, "cdrs:t:")) != -1) X { X switch (c) X { X case 'c': X calibrate++ ; X break ; X X case 'd': X debug++ ; X break ; X X case 'r': X rep = -1 ; X break ; X X case 's': X delay = atoi(optarg) ; X break ; X X case 't': X runtime = atoi(optarg) ; X break ; X X case '?': X err++ ; X } X } X X if (err || optind < argc) X { X (void) fprintf(stderr, X "usage: %s [ -cd ] [ -t time ]\n", argv[0]) ; X exit(2) ; X } X X if (delay) (void) sleep((unsigned) delay) ; X X if (calibrate) X { X measure(runtime) ; X X if ((cfile = fopen(CALFILE, "w")) == 0) X { X perror(CALFILE) ; X exit(1) ; X } X X (void) fprintf(cfile, "%f %f\n", process, speed) ; X X (void) fprintf(stderr, X "Calibrated process=%f, speed=%f\n", process, speed) ; X } X else X { X if ((cfile = fopen(CALFILE, "r")) == 0) X { X perror(CALFILE) ; X (void) fprintf(stderr, X "Perhaps you should run \"%s -c\" first.\n", argv[0]) ; X exit(1) ; X } X X if ( fscanf(cfile, "%lf %lf", &cprocess, &cspeed) != 2 X || cprocess == 0 X || cspeed == 0 X ) X { X (void) fprintf(stderr, X "%s file does not contain calibrated speed.\n", CALFILE) ; X } X X if (signal(SIGINT, SIG_IGN) != SIG_IGN) X (void) signal(SIGINT, sigint) ; X X for (;;) X { X measure(runtime) ; X X#if 0 X process /= cprocess ; X#endif X speed /= cspeed ; X X if (debug) X { X (void) fprintf(stderr, "normalized process=%.5f, speed=%.5f\n", X process, speed) ; X } X X (void) sprintf(buf, X "TIME process=%.1f, interrupt=%.1f, total=%.1f\n", X 100 * (1 - process) * speed, X 100 * (1 - speed), X 100 * (1 - process * speed)) ; X X (void) write(2, buf, (unsigned) strlen(buf)) ; X X if (rep == 0 || interrupt) break ; X X rep-- ; X } X } X X return(0) ; X} END_OF_cpu.c if test 7481 -ne `wc -c <cpu.c`; then echo shar: \"cpu.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f ibench -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"ibench\" else echo shar: Extracting \"ibench\" \(1959 characters\) sed "s/^X//" >ibench <<'END_OF_ibench' X#!/bin/sh X# X#################################################### X# This software released to the public domain # X# without restrictions of any kind. # X#################################################### X# X# @(#)ibench 3.1 9/22/89 X Xdef_baud="9600 exta extb" Xdef_flow="ixoff" Xdef_mode="-icanon" X Xtty= Xbaud= Xmode= Xlen= Xmin=0 X Xwhile [ "$1" ] Xdo X case "$1" in X X 50|75|110|1200|2400|4800|9600|19200|38400|exta|extb) X def_baud= X baud="$baud $1" X ;; X X [1-9]|1[0-6]) X min=$1 X ;; X X 19200,exta|38400,extb|exta,19200|extb,38400) X def_baud= X baud="$baud $1" X ;; X X ixoff|-ixoff) X def_flow= X flow="$flow $1" X ;; X X icanon|-icanon) X def_mode= X mode="$mode $1" X ;; X X /dev/*) X tty="$tty $1" X ;; X X tty*|cu*) X tty="$tty /dev/$1" X ;; X X *) X tty="$tty /dev/tty$1" X ;; X esac X X shift Xdone X Xbaud="$def_baud $baud" Xmode="$def_mode $mode" Xflow="$def_flow $flow" X Xctty=`expr "$tty" : ' *\([^ ]*\)'` X Xlastb=0 Xfor b in $baud Xdo X b1=`expr "$b" : '\(.*\),.*' \| "$b"` ; X b2=`expr "$b" : '.*,\(.*\)' \| "$b"` ; X X if [ $lastb != 0 -a $b1 != $lastb ] X then X for i in $tty X do X ( X stty $lastb -echo -icanon -opost X perf -c "stty $b2" X sleep 5 X ) <$i >$i & X done X wait X fi X lastb=$b1 X X case $b1 in X 50) vol=574000 ;; X 75) vol=768000 ;; X 110) vol=1152000 ;; X 1200) vol=12000 ;; X 2400) vol=24000 ;; X 4800) vol=48000 ;; X 9600) vol=96000 ;; X exta|19200) vol=192000 ;; X extb|38400) vol=384000 ;; X esac X X X for f in $flow X do X for m in $mode X do X t= X n=0 X X for i in $tty X do X t="$t $i" X n=`expr $n + 1` X X [ $n -ge $min ] || continue X X msg="tty=$n, baud=$b1, mode=$m, flow=$f" X echo "SEND $msg" X X ( X stty $b1 -echo -opost -icanon X perf -e "TEST $msg" X perf -c "(sleep 30 ; cpu -t 50)&" X ) <$ctty >$ctty X X for j in $t X do X ( X stty $b1 -opost -echo -icanon ixon X perf -c "stty $m $f" X sleep 5 X perf $vol X ) <$j >$j & X done X X wait X sleep 10 X done X done X done Xdone 2>&1 END_OF_ibench if test 1959 -ne `wc -c <ibench`; then echo shar: \"ibench\" unpacked with wrong size! fi # end of overwriting check fi if test -f iprint -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"iprint\" else echo shar: Extracting \"iprint\" \(2150 characters\) sed "s/^X//" >iprint <<'END_OF_iprint' X#!/bin/sh X# X#################################################### X# This software released to the public domain # X# without restrictions of any kind. # X#################################################### X# X# @(#)iprint 3.1 9/22/89 X X( sed -ne ' X /^#/p X s/exta/19200/ X s/extb/38400/ X s/.*TEST.*tty=\([^,]*\).*baud=\([^,]*\).*mode=\([^,]*\).*flow=\([^,]*\).*/TEST \1 \2 \3 \4/p X s/.*TIME.*process=\([^,]*\).*interrupt=\([^,]*\).*total=\([^,]*\).*/TIME \1 \2 \3/p X s/.*INPUT.*IN.*cps=\([^,]*\).*real=\([^,]*\).*user=\([^,]*\).*sys=\([^,]*\).*errs=\([^,]*\).*stray=\([^,]*\).*/CAL \1 \2 \3 \4 \5 \6/p X s/.*dev.*IN.*cps=\([^,]*\).*real=\([^,]*\).*user=\([^,]*\).*sys=\([^,]*\).*errs=\([^,]*\).*stray=\([^,]*\).*/IN \1 \2 \3 \4 \5 \6/p X ' $* \ X| awk ' X BEGIN { X tty = 0 ; n = 0 ; X cps = 0 ; ; errs = 0 ; stray = 0 ; X process = 0 ; interrupt = 0 ; total = 0 ; X usercost = 48.2 / 85499 ; X } X X /^#/ { print ; next } X X /^TIME/ { X process += $2 ; interrupt += $3 ; total += $4 ; X } X X /^CAL/ { X usercost = $4 / $2 ; X } X X /^IN/ { X n += 1 ; X cps += $2 ; errs += $6 ; stray += $7 ; X } X X /^TEST/ { X if (n != 0) { X if (n != tty) { X print "**** Following results suspect:" ; X } X X cpu = total - cps * usercost ; X printf("%5d %9s %10s %8s %8.1f %8.1f %10.2f %8.2f\n", \ X tty, baud, mode, flow, cps/n, errs, \ X cpu, 1000*cpu/cps) ; X } X X n = 0 ; X cps = 0 ; errs = 0 ; stray = 0 ; X process = 0 ; interrupt = 0 ; total = 0 ; X X if (tty == 0) { X printf("\n\n") ; X printf(" ports baud mode flow cps errs %%sys %%host\n") ; X printf(" ----- ------ ------ ------ ----- ------ ------- ------\n") ; X } X X lastbaud = baud ; lastmode = mode ; lastflow = flow ; X tty = $2 ; baud = $3 ; mode = $4 ; flow = $5 ; X X if (baud != lastbaud || lastmode != mode || lastflow != flow) { X printf("\n") ; X } X } X X /^\#/ { print } X X END { X if (n != 0) { X cpu = total - cps * usercost ; X printf("%5d %9s %10s %8s %8.1f %8.1f %10.2f %8.2f\n", \ X tty, baud, mode, flow, cps/n, errs, \ X cpu, 1000*cpu/cps) ; X } X } X ' X) END_OF_iprint if test 2150 -ne `wc -c <iprint`; then echo shar: \"iprint\" unpacked with wrong size! fi # end of overwriting check fi if test -f islave -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"islave\" else echo shar: Extracting \"islave\" \(737 characters\) sed "s/^X//" >islave <<'END_OF_islave' X#!/bin/sh X# X#################################################### X# This software released to the public domain # X# without restrictions of any kind. # X#################################################### X# X# @(#)islave 3.2 9/22/89 X Xbaud="9600" Xtty= X Xwhile [ "$1" ] Xdo X case "$1" in X X 50|75|110|1200|2400|4800|9600|19200|38400|exta|extb) X baud="$1" X ;; X X /dev/*) X def_tty= X tty="$tty $1" X ;; X X tty*|cu*) X tty="$tty /dev/$1" X ;; X X *) X tty="$tty /dev/tty$1" X ;; X esac X X shift Xdone X Xperf 999999 2>/dev/null | perf -s 2>&1 X Xfor i in $tty Xdo X ( X stty $baud eof '^a' erase '^h' kill '^u' \ X cs7 parenb -parodd -icrnl -istrip -ignpar inpck \ X -icanon -ixon -ixoff -echo -opost X perf X ) >$i <$i & Xdone 2>&1 X Xwait END_OF_islave if test 737 -ne `wc -c <islave`; then echo shar: \"islave\" unpacked with wrong size! fi # end of overwriting check fi if test -f obench -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"obench\" else echo shar: Extracting \"obench\" \(1296 characters\) sed "s/^X//" >obench <<'END_OF_obench' X#!/bin/sh X# X#################################################### X# This software released to the public domain # X# without restrictions of any kind. # X#################################################### X# X# @(#)obench 3.3 10/25/89 X Xdef_baud="9600 exta extb" Xdef_mode="opost -opost" X Xtty= Xbaud= Xmode= Xlen= Xmin=0 X Xwhile [ "$1" ] Xdo X case "$1" in X X 50|75|110|1200|2400|4800|9600|19200|38400|exta|extb) X def_baud= X baud="$baud $1" X ;; X X [1-9]|1[0-6]) X min=$1 X ;; X X opost|-opost) X def_mode= X mode="$mode $1" X ;; X X /dev/*) X tty="$tty $1" X ;; X X tty*|cu*) X tty="$tty /dev/$1" X ;; X X *) X tty="$tty /dev/tty$1" X ;; X esac X X shift Xdone X Xbaud="$def_baud $baud" Xmode="$def_mode $mode" X X(perf -s 999999 >/dev/null) 2>&1 X Xfor b in $baud Xdo X case $b in X 50) vol=574000 ;; X 75) vol=768000 ;; X 110) vol=1152000 ;; X 1200) vol=12000 ;; X 2400) vol=24000 ;; X 4800) vol=48000 ;; X 9600) vol=96000 ;; X exta|19200) vol=192000 ;; X extb|38400) vol=384000 ;; X esac X X for m in $mode X do X t= X n=0 X X for i in $tty X do X t="$t $i" X n=`expr $n + 1` X X [ $n -ge $min ] || continue X X echo "TEST tty=$n, baud=$b, mode=$m" X X for j in $t X do X ( X stty $b $m -ixon -ixoff X sleep 10 X perf $vol X ) >$j <&1 & X done X X sleep 30 X cpu -t 50 X X wait X done X done Xdone 2>&1 END_OF_obench if test 1296 -ne `wc -c <obench`; then echo shar: \"obench\" unpacked with wrong size! fi # end of overwriting check fi if test -f oprint -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"oprint\" else echo shar: Extracting \"oprint\" \(1952 characters\) sed "s/^X//" >oprint <<'END_OF_oprint' X#!/bin/sh X# X#################################################### X# This software released to the public domain # X# without restrictions of any kind. # X#################################################### X# X# @(#)oprint 3.1 9/22/89 X X( sed -ne ' X /^#/p X s/exta/19200/ X s/extb/38400/ X s/.*TEST.*tty=\([^,]*\).*baud=\([^,]*\).*mode=\([^,]*\).*/TEST \1 \2 \3/p X s/.*OUTPUT.*OUT.*cps=\([^,]*\).*real=\([^,]*\).*user=\([^,]*\).*sys=\([^,]*\).*/CAL \1 \2 \3 \4/p X s/.*dev.*OUT.*cps=\([^,]*\).*real=\([^,]*\).*user=\([^,]*\).*sys=\([^,]*\).*/OUT \1 \2 \3 \4/p X s/.*TIME.*process=\([^,]*\).*interrupt=\([^,]*\).*total=\([^,]*\).*/TIME \1 \2 \3/p X ' $* \ X| tee junk \ X| awk ' X BEGIN { X tty = 0 ; n = 0 ; X process = 0 ; interrupt = 0 ; total = 0 ; X cps = 0 ; real = 0 ; X usercost = 42.2 / 85470 ; X } X X /^\#/ { print ; next } X X /^TIME/ { X process += $2 ; interrupt += $3 ; total += $4 ; X } X X /^CAL/ { X usercost = $4 / $2 ; X } X X /^OUT/ { X cps += $2 ; real += $3 ; X n += 1 ; X } X X /^TEST/ { X if (tty == 0) { X printf("\n\n") ; X printf(" ports baud mode cps real %%sys %%host\n") ; X printf(" ----- ------ ------ ----- ------ ----- ----\n") ; X } X X if (n != 0) { X if (n != tty) { X print "**** Following results suspect:" ; X } X X cpu = total - cps * usercost ; X printf("%5d %9s %10s %8.1f %9.1f %8.1f %8.2f\n", \ X tty, baud, mode, cps / n, real / n, \ X cpu, 1000 * cpu / cps) ; X } X X lastbaud=baud ; lastmode=mode ; X tty = $2 ; baud = $3 ; mode = $4 ; X X if (n != 0 && (baud != lastbaud || lastmode != mode)) { X printf("\n") ; X } X X n = 0 ; X process = 0 ; interrupt = 0 ; total = 0 ; X cps = 0 ; real = 0 ; X } X END { X if (n != 0) { X cpu = total - cps * usercost ; X printf("%5d %9s %10s %8.1f %9.1f %8.1f %8.2f\n", \ X tty, baud, mode, cps/n, real/n, \ X cpu, 1000 * cpu / cps) ; X } X } X ' X) END_OF_oprint if test 1952 -ne `wc -c <oprint`; then echo shar: \"oprint\" unpacked with wrong size! fi # end of overwriting check fi if test -f perf.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"perf.c\" else echo shar: Extracting \"perf.c\" \(16238 characters\) sed "s/^X//" >perf.c <<'END_OF_perf.c' X/* :ex:se ts=4 sw=4 This program formatted with tabs 4 */ X X/**************************************************** X * This software released to the public domain * X * without restrictions of any kind. * X ****************************************************/ X X/* X * NAME X * perf - Test I/O system PERFormance. X * X * SYNOPSIS X * perf [ -qsv ] [ -c command ] [ -e text ] X * [ -t throttle ] [ -x outcount ] [ outcount ... ] X * X * DESCRIPTION X * Perf measures the transmission of characters through X * a communication media, keeping statistics on throughput X * and system utilization. X * X * When the any of the options c, e, q, t or x, or an X * outcount is specified, the program runs in output mode; X * Otherwise it runs in input mode. A perf in output mode X * may be used to test a system I/O subsystem output speed X * directly, or its output may be fed through communication X * hardware back into a perf in input mode for input X * performance testing. X * X * -c shell_command Output the given shell command to be X * executed by the receiving perf program. X * X * -e text Output the given text to be displayed X * by the receiving perf program. X * X * -q Output code 99998, which tells the X * receiving perf to terminate. X * X * -s Silent option. Suppress warning messages. X * X * -t throttle Throttle the input by sleeping for X * one second every throttle characters. X * X * -v On input, print statistics showing X * the length and number of times a X * stream of characters was missed. X * X * -x outchar Output enough 6 digit + checksum X * codes to produce the given number of X * characters. X * X * outcount Same as -x outcount above. X * X * All data sent by an output perf can be interpreted by X * an input perf, but the data is all printable ASCII in X * a simple format so a human can understand it as well. X * X * To test system throughput, the perf program uses 6 digit X * sequential codes, with a checksum. This format allows X * the input program--or a human observer--to easily and X * quantitatively compare desired to actual data. X * X * For input testing, it is often valuable to send data X * from one system to another. In this mode, perf can X * pass diagnostics text and shell commands through the X * communications link. This allows the output system X * to control the overall test procedure, and provide a X * test log on the input system. X * X * To improve accuracy, on output a code of 99998 is output X * for about 10K characters before measurement begins and X * after measurement completes. This is done so the X * measurement is more likely to be done under steady-state X * conditions. X * X * WARNING X * The order of parameters 2 & 3 on setvbuf() vary from X * system, and are even inconsistent between the manuals X * and the libraries on stock system V.2. You are wise X * to check the order of the parameters on your system and X * set the SETVBUF #define accordingly. X */ X X#if !defined(lint) Xchar whatstring[] = "@(#)perf.c 3.1 9/22/89" ; X#endif X X#if sun X#define BSD 1 X#endif X X#if BSD X# include <sys/types.h> X# include <sys/time.h> X# include <sys/resource.h> X#else X# include <sys/types.h> X# include <sys/times.h> X# include <sys/param.h> X#endif X X#include <ctype.h> X#include <stdio.h> X X#define uchar unsigned char X#define ushort unsigned short X#define ulong unsigned long X Xextern char *optarg ; Xextern int optind ; X Xextern char *ttyname() ; Xextern long atol() ; Xextern unsigned sleep() ; X X#if BSD Xextern char *sprintf() ; X#else Xextern int sprintf() ; Xextern void exit() ; Xextern time_t times() ; X#endif X X X#if BSD X# define TICS 1000 /* Fractional seconds */ X# define MS(tv) (1000000L / TICS * (tv).tv_sec + (tv).tv_usec / TICS) X#else X# define TICS HZ X#endif X X X#define NDIG 6 /* Number of digits/code */ X#define MAXCODE 999999 /* Largest NDIG number */ X X#define NHEAD 10000 /* Number of header characters */ X#define NTRAIL 10000 /* Number of trailer characters */ X X#define CPL 9 /* Number of codes per line */ X#define BASE 0x3f /* Base character for checksum */ X X#define NCHAR(ncode) ((NDIG + 2) * (ncode) + 2 * (((ncode) + CPL - 1) / CPL)) X#define NCODE(nchar) (((nchar) * CPL) / (CPL * (NDIG + 2) + 2)) X X Xchar iobuf[3][BUFSIZ] ; X X/* X * Command options. X */ X Xint verbose ; /* Verbose error reporting */ Xlong throttle ; /* Max chars between sleep calls */ Xint silent ; /* Silent option */ Xint out ; /* Output test */ X X/* X * Misc globals. X */ X Xint linepos ; /* Code position in line */ Xchar *tname ; /* Input/output ttyname */ X X/* X * Statistics gathering. X */ X X#define MAXSTAT 100 /* Gap max for statistics */ Xint gap[MAXSTAT] ; /* Statistics on code gaps */ X X X/************************************************************* X * Output a numeric code sequence * X *************************************************************/ X Xoutcode(v) Xregister long v ; X{ X register int ch ; X register char *p ; X static char digits[NDIG] ; X static long lastv ; X X if (v == lastv) X { X p = &digits[NDIG] ; X } X else if (v == lastv + 1) X { X lastv++ ; X for (p = digits ; *p == 9 ;) *p++ = 0 ; X *p += 1 ; X p = &digits[NDIG] ; X } X else X { X lastv = v ; X for (p = digits ; p != &digits[NDIG] ;) X { X *p++ = v % 10 ; X v /= 10 ; X } X } X X v = 0 ; X while (p != &digits[0]) X { X ch = *--p ; X v += (v << 4) + ch ; X ch += '0' ; X (void) putc(ch, stdout) ; X } X X ch = (v & 0x3f) + BASE ; X (void) putc(ch, stdout) ; X X ch = ((v >> 6) & 0x3f) + BASE ; X (void) putc(ch, stdout) ; X X if (++linepos == CPL) X { X (void) printf("\r\n") ; X linepos = 0 ; X } X} X X X X/*************************************************************** X * Close out the current line * X ***************************************************************/ X Xcloseline() X{ X if (linepos) X { X (void) printf("\r\n") ; X linepos = 0 ; X } X} X X X X/************************************************************ X * Send text to a remote * X ************************************************************/ X Xsendtext(prefix, text) Xint prefix ; Xchar *text ; X{ X int ch ; X unsigned check ; X X closeline() ; X X for (;;) X { X check = 0 ; X (void) fputc(prefix, stdout) ; X X while ((ch = *text++) && ch != '\n') X { X (void) fputc(ch, stdout) ; X check = 17 * check + ch ; X } X X (void) fputc((int)(check & 0x3f) + BASE, stdout) ; X check >>= 6 ; X (void) fputc((int)(check & 0x3f) + BASE, stdout) ; X X (void) printf("\r\n") ; X X if (ch == 0) break ; X } X} X X X X/*************************************************************** X * Transmit a given number of output codes * X ***************************************************************/ X Xtransmit(ncode) Xlong ncode ; X{ X long code ; X ulong real ; X ulong user ; X ulong sys ; X int cps ; X char buf[200] ; X X#if BSD X struct timeval tv ; X struct rusage ru ; X#else X struct tms tms ; X#endif X X /* X * Output header codes to fill the output queue so we X * will get a better idea of the true transmission times. X */ X X (void) printf("\r\n") ; X X linepos = 0 ; X code = NCODE(NHEAD) ; X while (--code >= 0) outcode((long) (MAXCODE - 1)) ; X closeline() ; X (void) fflush(stdout) ; X X /* X * Get time statistics. X */ X X#if BSD X (void) gettimeofday(&tv, (struct timezone *)0) ; X real = MS(tv) ; X X (void) getrusage(RUSAGE_SELF, &ru) ; X user = MS(ru.ru_utime) ; X sys = MS(ru.ru_stime) ; X#else X real = times(&tms) ; X user = tms.tms_utime ; X sys = tms.tms_stime ; X#endif X X /* X * Output ncode actual codes. X */ X X for (code = 0 ; code < ncode ; code++) outcode(code) ; X closeline() ; X (void) fflush(stdout) ; X X /* X * Figure the system resources used in the X * duration of the test. X */ X X#if BSD X (void) gettimeofday(&tv, (struct timezone *)0) ; X real = MS(tv) - real ; X X (void) getrusage(RUSAGE_SELF, &ru) ; X user = MS(ru.ru_utime) - user ; X sys = MS(ru.ru_stime) - sys ; X cps = 1000L * NCHAR(ncode) / (real ? real : 1) ; X#else X real = times(&tms) - real ; X cps = TICS * NCHAR(ncode) / (real ? real : 1) ; X user = tms.tms_utime - user ; X sys = tms.tms_stime - sys ; X#endif X X if (real == 0) real = 1 ; X X /* X * Output trailer codes to end the sequence. X */ X X code = NCODE(NTRAIL) ; X while (--code >= 0) outcode((long) (MAXCODE - 1)) ; X closeline() ; X X (void) fflush(stdout) ; X X /* X * Output results. X */ X X (void) sprintf(buf, X "%s : OUT cps=%ld, real=%.2f, user=%.1f, sys=%.1f\n", X tname, cps, (double) real / TICS, X 100.0 * (double) user / (double) real, X 100.0 * (double) sys / (double) real) ; X X (void) write(2, buf, (unsigned) strlen(buf)) ; X} X X X/*********************************************************** X * Honor a text escape from the remote. * X ***********************************************************/ X Xreadtext(prefix) Xint prefix ; X{ X int ch ; X int n ; X int i ; X int check ; X char buf[1000] ; X X n = 0 ; X X for (;;) X { X if ((ch = fgetc(stdin)) == EOF) break ; X ch &= 0x7f ; X X if (ch == '\r' || ch == '\n') break ; X X if (n < sizeof(buf)) X { X buf[n] = ch ; X } X n++ ; X } X X if (n < 2 || n > sizeof(buf)) X { X (void) fprintf(stderr, "Text size error!\n", prefix) ; X return ; X } X X n -= 2 ; X check = 0 ; X X for (i = 0 ; i < n ; i++) check = 17 * check + buf[i] ; X X if ( ((check & 0x3f) + BASE) != buf[n] X || (((check >>= 6) & 0x3f) + BASE) != buf[n+1] X ) X { X (void) fprintf(stderr, "Text checksum error!\n", prefix) ; X return ; X } X X buf[n] = 0 ; X X if (prefix == '!') (void) system(buf) ; X X if (prefix == '#') X { X (void) fputs(buf, stderr) ; X (void) fputc('\n', stderr) ; X } X} X X X X/*********************************************************** X * Receive data routine. * X ***********************************************************/ X Xreceive() X{ X register int ch ; X register long v ; X int d ; X int i ; X int n ; X int lch ; X unsigned short s ; X ulong real ; X ulong user ; X ulong sys ; X long code ; X long cps ; X long error ; X long trash ; X long scode ; X long incount ; X char buf[200] ; X X#if BSD X struct timeval tv ; X struct rusage ru ; X#else X struct tms tms ; X#endif X X real = 0 ; X user = 0 ; X sys = 0 ; X trash = 0 ; X error = 0 ; X code = MAXCODE - 1 ; X scode = 0 ; X incount = 0 ; X X ch = getc(stdin) ; X X /* X * Loop to read codes until and exit code appears. X */ X X for (;;) X { X v = 0 ; X d = 0 ; X s = 0 ; X X if (++incount >= throttle) X { X (void) sleep(1) ; X incount = 0 ; X } X X /* X * Ignore white space, detect EOF, and scan X * until a digit appears. X */ X X lch = '\n' ; X X for (;;) X { X if (ch == EOF) X { X if (!silent) (void) fprintf(stderr, "Exiting on EOF!\n") ; X exit(1) ; X } X X ch &= 0x7f ; X X if (ch >= '0' && ch <= '9') break ; X X if (lch == '\n' && (ch == '!' || ch == '#')) X { X readtext(ch) ; X lch = '\n' ; X } X else if X ( ch != '\r' && ch != '\n' X && (ch < BASE || ch > (BASE + 0x3f)) X ) X trash++ ; X X lch = '\n' ; X ch = getc(stdin) ; X } X X /* X * Pick up a digit string. X */ X X while (isdigit(ch)) X { X ch -= '0' ; X v = 10 * v + ch ; X s += (s << 4) + ch ; X d++ ; X if ((ch = getc(stdin)) == EOF) break ; X ch &= 0x7f ; X } X X /* X * Process checksum. X */ X X if (d != NDIG || (ch - BASE) != (s & 0x3f)) continue ; X X if ((ch = getc(stdin)) == EOF) continue ; X ch &= 0x7f ; X X if ((ch - BASE) != ((s >> 6) & 0x3f)) continue ; X X ch = getc(stdin) ; X X /* X * Pick up end of sequence or quit indicator. X */ X X if (v >= MAXCODE - 1) X { X if (code != MAXCODE - 1) X { X code -= scode ; X X /* X * Figure resources used, and print results. X */ X X#if BSD X (void) gettimeofday(&tv, (struct timezone *)0) ; X real = MS(tv) - real ; X X (void) getrusage(RUSAGE_SELF, &ru) ; X user = MS(ru.ru_utime) - user ; X sys = MS(ru.ru_stime) - sys ; X cps = 1000L * NCHAR(code) / (real ? real : 1) ; X#else X real = times(&tms) - real ; X cps = TICS * NCHAR(code) / (real ? real : 1) ; X user = tms.tms_utime - user ; X sys = tms.tms_stime - sys ; X#endif X if (real == 0) real = 1 ; X X (void) sprintf(buf, X "%s : IN cps=%ld, real=%.2f, user=%.1f, sys=%.1f, errs=%ld, stray=%ld\n", X tname, cps, (double)real / TICS, X 100.0 * (double) user / (double) real, X 100.0 * (double) sys / (double) real, X error, trash) ; X X (void) write(2, buf, (unsigned) strlen(buf)) ; X X /* X * Print verbose error statistics. X */ X X if (verbose && error) X { X (void) fprintf(stderr, X "%s : Sequence gaps were:\n\t", tname) ; X X n = 0 ; X for (i = 0 ; i < MAXSTAT ; i++) X { X if (gap[i]) X { X if (n == 6) X { X (void) fprintf(stderr, "\n\t") ; X n = 0 ; X } X (void) fprintf(stderr, X "%4d:%4d", NCHAR(i+1), gap[i]) ; X n++ ; X } X } X if (n) (void) fprintf(stderr, "\n") ; X } X } X X /* X * Quit when the maximum input code is X * received. X */ X X if (v == MAXCODE) X { X (void) fprintf(stderr, X "%s : Received exit code, quitting\n", tname) ; X exit(0) ; X } X if (code != MAXCODE - 1) X { X code = MAXCODE - 1 ; X } X } X X /* X * Handle expected sequence number. X */ X X else if (v == code) code++ ; X X /* X * Handle sequence lower than our current sequence, X * indicating a restart. X */ X X else if (v < code) X { X if (code != MAXCODE - 1) X { X (void) fprintf(stderr, X "%s : Incomplete sequence aborted\n", tname) ; X } X X for (i = 0 ; i < MAXSTAT ; i++) gap[i] = 0 ; X X trash = 0 ; X error = 0 ; X code = v + 1 ; X X /* X * Get start time statistics. X */ X X#if BSD X (void) gettimeofday(&tv, (struct timezone *)0) ; X real = MS(tv) ; X X (void) getrusage(RUSAGE_SELF, &ru) ; X user = MS(ru.ru_utime) ; X sys = MS(ru.ru_stime) ; X#else X real = times(&tms) ; X user = tms.tms_utime ; X sys = tms.tms_stime ; X#endif X X scode = v ; X } X X /* X * Handle sequence greater than our expected X * sequence. X */ X X else X { X i = v - code ; X error += i ; X if (i > MAXSTAT) i = MAXSTAT ; X gap[i-1]++ ; X code = v + 1 ; X } X } X} X X X X/************************************************************* X * Main Program * X *************************************************************/ X Xmain(argc, argv) Xint argc ; Xchar **argv ; X{ X int quit = 0 ; X int i ; X int ch ; X long nchar ; X X#if SETVBUF X (void) setvbuf(stdin, _IOFBF, iobuf[0], sizeof(iobuf[0])) ; X (void) setvbuf(stdout, _IOFBF, iobuf[1], sizeof(iobuf[0])) ; X (void) setvbuf(stderr, _IOLBF, iobuf[2], sizeof(iobuf[0])) ; X#else X (void) setvbuf(stdin, iobuf[0], _IOFBF, sizeof(iobuf[0])) ; X (void) setvbuf(stdout, iobuf[1], _IOFBF, sizeof(iobuf[0])) ; X (void) setvbuf(stderr, iobuf[2], _IOLBF, sizeof(iobuf[0])) ; X#endif X X /* X * Break out options. X */ X X throttle = 9999999 ; X X while ((ch = getopt(argc, argv, "c:e:qst:vx:")) != -1) X { X switch (ch) X { X case 'c': X out++ ; X sendtext('!', optarg) ; X break ; X X case 'e': X out++ ; X sendtext('#', optarg) ; X break ; X X case 'q': X out++ ; X quit++ ; X break ; X X case 's': X silent++ ; X break ; X X case 't': X throttle = atoi(optarg) ; X throttle = NCODE(throttle) ; X break ; X X case 'v': X verbose++ ; X break ; X X case 'x': X out++ ; X nchar = atoi(optarg) ; X transmit(NCODE(nchar)) ; X break ; X X default: X (void) fprintf(stderr, X "usage: %s [ -qv ] [ nchar ]\n", argv[0]) ; X exit(2) ; X } X } X X /* X * Check for terminal input/output. X */ X X if (optind != argc) out++ ; X X if (out) X { X tname = ttyname(1) ; X if (tname == 0) X { X if (!silent) X (void) fprintf(stderr, "Standard output is not a terminal!\n") ; X tname = "OUTPUT" ; X } X } X else X { X tname = ttyname(0) ; X if (tname == 0) X { X if (!silent) X (void) fprintf(stderr, "Standard input is not a terminal!\n") ; X tname = "INPUT" ; X } X } X X /* X * Output code counts as requested. X */ X X while (optind < argc) X { X nchar = atol(argv[optind]) ; X if (nchar > 0) transmit(NCODE(nchar)) ; X optind++ ; X } X X /* X * Output quit codes. X */ X X if (quit) X { X for (i = 0 ; i < NTRAIL ; i++) X { X outcode((long) MAXCODE) ; X } X closeline() ; X } X X (void) fflush(stdout) ; X X /* X * If no code counts or the quit flag, this is X * a receive data test. X */ X X if (!out) X { X receive() ; X exit(0) ; X } X X return(0) ; X} END_OF_perf.c if test 16238 -ne `wc -c <perf.c`; then echo shar: \"perf.c\" unpacked with wrong size! fi # end of overwriting check fi echo shar: End of shell archive. exit 0