[comp.sources.misc] v09i004: TBENCH - tty benchmark programs

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