home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume9 / tbench / cpu.c next >
C/C++ Source or Header  |  1989-11-12  |  7KB  |  381 lines

  1. /*     :ex:se ts=4 sw=4    This program formatted with tabs 4 */
  2.  
  3. /****************************************************
  4.  *     This software released to the public domain  *
  5.  *     without restrictions of any kind.            *
  6.  ****************************************************/
  7.  
  8. /*
  9.  *    NAME
  10.  *        cpu - CPU activity sensor
  11.  *
  12.  *    SYNOPSIS
  13.  *        cpu [ -cdr ] [-s delay ] [ -t time ]
  14.  *
  15.  *    DESCRIPTION
  16.  *        CPU is a program to detect the overall processor
  17.  *        activity present in a system as part of performance
  18.  *        testing.  CPU must be calibrated on an idle
  19.  *        system, where it times a test loop and writes
  20.  *        the results to the file /tmp/.cpu.   Thereafter
  21.  *        CPU may be run at any time when the system is
  22.  *        under load.   Using CPU statistics provided by
  23.  *        the system, and by measuring the test loop slowdown,
  24.  *        the program can approximate general system CPU loading.
  25.  *
  26.  *        -c            Calibrate.  Should be run when the system
  27.  *                    is as idle as possible; single user mode
  28.  *                    is best.
  29.  *
  30.  *        -d            Turn on debugging flags.
  31.  *
  32.  *        -r            Test repeatedly until interrupted.
  33.  *
  34.  *        -s delay    Sleep for the given delay time before
  35.  *                    beginning the test.
  36.  *
  37.  *        -t time        Run the test for time seconds.
  38.  *                
  39.  *        On completion, CPU outputs the following 3 time values.
  40.  *
  41.  *        process        The amount of time the system reported
  42.  *                    that other processes were running.
  43.  *
  44.  *        interrupt    The slowdown of the test loop not reflected
  45.  *                    by the system statistics.  Most likely this
  46.  *                    time was consumed by interrupt routines, by
  47.  *                    task switching overhead, or because activity
  48.  *                    was synchronized to the system clock.
  49.  *
  50.  *        total        The total slowdown of the test loop relative
  51.  *                    to the speed measured at calibration time.
  52.  *
  53.  *        The total time is the most interesting, since it reflects
  54.  *        the real processor utilization abosorbed by other processes.
  55.  *        Proper use of the other two numbers is left as a problem
  56.  *        for the reader.
  57.  *
  58.  *    WARNINGS
  59.  *        CPU is astoundingly inaccurate in systems with different
  60.  *        speed memories.  In some systems (eg i386 with 16 bit
  61.  *        memory on the AT bus) it is not uncommon for calibration
  62.  *        runs to vary by a factor of 2 or more.  There is no
  63.  *        solution but to change the memory or find another machine.
  64.  *
  65.  *        The order of parameters 2 & 3 on setvbuf() vary from
  66.  *        system, and are even inconsistent between the manuals
  67.  *        and the libraries on stock system V.2.  You are wise
  68.  *        to check the order of the parameters on your system and
  69.  *        set the SETVBUF #define accordingly.
  70.  */
  71.  
  72. #if !defined(lint)
  73. char whatstring[] = "@(#)cpu.c    3.1 9/22/89" ;
  74. #endif
  75.  
  76. #if sun
  77. #define BSD 1
  78. #endif
  79.  
  80. #if BSD
  81. #    include <sys/types.h>
  82. #    include <sys/time.h>
  83. #    include <sys/resource.h>
  84. #else
  85. #    include <sys/types.h>
  86. #    include <sys/times.h>
  87. #    include <sys/param.h>
  88. #endif
  89.  
  90. #include <signal.h>
  91. #include <ctype.h>
  92. #include <stdio.h>
  93.  
  94. #define uchar unsigned char
  95. #define ushort unsigned short
  96. #define ulong unsigned long
  97.  
  98. extern char *optarg ;
  99. extern int optind ;
  100.  
  101. extern char *ttyname() ;
  102. extern long atol() ;
  103. extern void (*signal())() ;
  104. extern unsigned sleep() ;
  105.  
  106. #if BSD
  107. #else
  108. extern unsigned alarm() ;
  109. extern void exit() ;
  110. extern void perror() ;
  111. extern time_t times() ;
  112. #endif
  113.  
  114.  
  115. #if BSD
  116. #    define TICS 1000        /* Fractional seconds */
  117. #    define MS(tv) (1000000L / TICS * (tv).tv_sec + (tv).tv_usec / TICS)
  118. #else
  119. #    define TICS HZ
  120. #endif
  121.  
  122. #define CALFILE "/tmp/.cpu"
  123.  
  124.  
  125. double speed ;                /* Speed of the processor running */
  126. double process ;            /* Amount of the machine allocated to us */
  127.  
  128. int debug ;                    /* Debug flag */
  129. int delay ;                    /* Delay before start */
  130. int timeout ;                /* Alarm occurred flag */
  131. int interrupt ;                /* Got an interrupt */
  132.  
  133. ulong rep ;                    /* Repeat count */
  134.  
  135.  
  136.  
  137. /*******
  138.  *    Catch interrupts.
  139.  */
  140.  
  141. sigalrm()
  142. {
  143.     timeout = 1 ;
  144. }
  145.  
  146. sigint()
  147. {
  148.     interrupt = 1 ;
  149. }
  150.  
  151.  
  152. /*******
  153.  *    delay - Routine to chew time.
  154.  */
  155.  
  156. hog()
  157. {
  158.     static int a = 1 ;
  159.     static int b = 2 ;
  160.     static int c = 3 ;
  161.  
  162.     a += b ;
  163.     b += c ;
  164.     c += a ;
  165. }
  166.  
  167.  
  168. /*******
  169.  *    measure - Procedure to measure our access to the CPU.
  170.  */
  171.  
  172. measure(runtime)
  173. int runtime ;                    /* Time period */
  174. {
  175.     ulong real ;
  176.     ulong sys ;
  177.     ulong user ;
  178.     ulong count ;
  179.  
  180. #if BSD
  181.     struct timeval tv ;
  182.     struct rusage ru ;
  183. #else
  184.     struct tms tms ;
  185. #endif
  186.  
  187.     /*
  188.      *    Get real time and system time.
  189.      */
  190.  
  191. #if BSD
  192.     (void) gettimeofday(&tv, (struct timezone *)0) ;
  193.     real = MS(tv) ;
  194.  
  195.     (void) getrusage(RUSAGE_SELF, &ru) ;
  196.     user = MS(ru.ru_utime) ;
  197.     sys = MS(ru.ru_stime) ;
  198. #else
  199.     real = times(&tms) ;
  200.     user = tms.tms_utime ;
  201.     sys = tms.tms_stime ;
  202. #endif
  203.  
  204.     if (debug) (void) fprintf(stderr,"Cpu started\n") ;
  205.  
  206.     timeout = 0 ;
  207.     count = 0 ;
  208.  
  209.     (void) signal(SIGALRM, sigalrm) ;
  210.     (void) alarm((unsigned) runtime) ;
  211.  
  212.     (void) nice(40) ;
  213.  
  214.     while (!timeout && !interrupt)
  215.     {
  216.         hog() ;
  217.         count++ ;
  218.     }
  219.  
  220.     (void) nice(-40) ;
  221.  
  222. #if BSD
  223.     (void) gettimeofday(&tv, (struct timezone *)0) ;
  224.     real = MS(tv) - real ;
  225.  
  226.     (void) getrusage(RUSAGE_SELF, &ru) ;
  227.     user = MS(ru.ru_utime) - user ;
  228.     sys = MS(ru.ru_stime) - sys ;
  229. #else
  230.     real = times(&tms) - real ;
  231.     user = tms.tms_utime - user ;
  232.     sys = tms.tms_stime - sys ;
  233. #endif
  234.  
  235.     process = (double) user / (double) real ;
  236.     speed = user ? (double) count / (double) user : 0.0 ;
  237.  
  238.     if (debug)
  239.     {
  240.         (void) fprintf(stderr,
  241.             "real=%ld, sys=%ld, user=%ld, count=%ld\n",
  242.             real, sys, user, count) ;
  243.         (void) fprintf(stderr, "raw process=%.5f, speed=%.5f\n",
  244.             process, speed) ;
  245.     }
  246. }
  247.  
  248.  
  249.  
  250. main(argc, argv)
  251. int argc ;
  252. char **argv ;
  253. {
  254.     double cprocess ;
  255.     double cspeed ;
  256.     int calibrate ;
  257.     int runtime = 30 ;
  258.     int err ;
  259.     int c ;
  260.     FILE *cfile ;
  261.     char iobuf[1024] ;
  262.     char buf[200] ;
  263.  
  264. #if SETVBUF
  265.     (void) setvbuf(stderr, _IOLBF, iobuf, sizeof(iobuf)) ;
  266. #else
  267.     (void) setvbuf(stderr, iobuf, _IOLBF, sizeof(iobuf)) ;
  268. #endif
  269.  
  270.     (void) nice(-40) ;
  271.  
  272.     calibrate = 0 ;
  273.     err = 0 ;
  274.  
  275.     while ((c = getopt(argc, argv, "cdrs:t:")) != -1)
  276.     {
  277.         switch (c)
  278.         {
  279.         case 'c':
  280.             calibrate++ ;
  281.             break ;
  282.         
  283.         case 'd':
  284.             debug++ ;
  285.             break ;
  286.         
  287.         case 'r':
  288.             rep = -1 ;
  289.             break ;
  290.         
  291.         case 's':
  292.             delay = atoi(optarg) ;
  293.             break ;
  294.  
  295.         case 't':
  296.             runtime = atoi(optarg) ;
  297.             break ;
  298.         
  299.         case '?':
  300.             err++ ;
  301.         }
  302.     }
  303.  
  304.     if (err || optind < argc)
  305.     {
  306.         (void) fprintf(stderr,
  307.             "usage: %s [ -cd ] [ -t time ]\n", argv[0]) ;
  308.         exit(2) ;
  309.     }
  310.  
  311.     if (delay) (void) sleep((unsigned) delay) ;
  312.  
  313.     if (calibrate)
  314.     {
  315.         measure(runtime) ;
  316.  
  317.         if ((cfile = fopen(CALFILE, "w")) == 0)
  318.         {
  319.             perror(CALFILE) ;
  320.             exit(1) ;
  321.         }
  322.  
  323.         (void) fprintf(cfile, "%f %f\n", process, speed) ;
  324.  
  325.         (void) fprintf(stderr,
  326.             "Calibrated process=%f, speed=%f\n", process, speed) ;
  327.     }
  328.     else
  329.     {
  330.         if ((cfile = fopen(CALFILE, "r")) == 0)
  331.         {
  332.             perror(CALFILE) ;
  333.             (void) fprintf(stderr,
  334.                 "Perhaps you should run \"%s -c\" first.\n", argv[0]) ;
  335.             exit(1) ;
  336.         }
  337.  
  338.         if    (    fscanf(cfile, "%lf %lf", &cprocess, &cspeed) != 2
  339.             ||    cprocess == 0
  340.             ||    cspeed == 0
  341.             )
  342.         {
  343.             (void) fprintf(stderr,
  344.                 "%s file does not contain calibrated speed.\n", CALFILE) ;
  345.         }
  346.  
  347.         if (signal(SIGINT, SIG_IGN) != SIG_IGN)
  348.             (void) signal(SIGINT, sigint) ;
  349.  
  350.         for (;;)
  351.         {
  352.             measure(runtime) ;
  353.  
  354. #if 0
  355.             process /= cprocess ;
  356. #endif
  357.             speed /= cspeed ;
  358.  
  359.             if (debug)
  360.             {
  361.                 (void) fprintf(stderr, "normalized process=%.5f, speed=%.5f\n",
  362.                     process, speed) ;
  363.             }
  364.  
  365.             (void) sprintf(buf,
  366.                 "TIME process=%.1f, interrupt=%.1f, total=%.1f\n",
  367.                 100 * (1 - process) * speed,
  368.                 100 * (1 - speed),
  369.                 100 * (1 - process * speed)) ;
  370.  
  371.             (void) write(2, buf, (unsigned) strlen(buf)) ;
  372.             
  373.             if (rep == 0 || interrupt) break ;
  374.  
  375.             rep-- ;
  376.         }
  377.     }
  378.  
  379.     return(0) ;
  380. }
  381.