home *** CD-ROM | disk | FTP | other *** search
- /* :ex:se ts=4 sw=4 This program formatted with tabs 4 */
-
- /****************************************************
- * This software released to the public domain *
- * without restrictions of any kind. *
- ****************************************************/
-
- /*
- * NAME
- * cpu - CPU activity sensor
- *
- * SYNOPSIS
- * cpu [ -cdr ] [-s delay ] [ -t time ]
- *
- * DESCRIPTION
- * CPU is a program to detect the overall processor
- * activity present in a system as part of performance
- * testing. CPU must be calibrated on an idle
- * system, where it times a test loop and writes
- * the results to the file /tmp/.cpu. Thereafter
- * CPU may be run at any time when the system is
- * under load. Using CPU statistics provided by
- * the system, and by measuring the test loop slowdown,
- * the program can approximate general system CPU loading.
- *
- * -c Calibrate. Should be run when the system
- * is as idle as possible; single user mode
- * is best.
- *
- * -d Turn on debugging flags.
- *
- * -r Test repeatedly until interrupted.
- *
- * -s delay Sleep for the given delay time before
- * beginning the test.
- *
- * -t time Run the test for time seconds.
- *
- * On completion, CPU outputs the following 3 time values.
- *
- * process The amount of time the system reported
- * that other processes were running.
- *
- * interrupt The slowdown of the test loop not reflected
- * by the system statistics. Most likely this
- * time was consumed by interrupt routines, by
- * task switching overhead, or because activity
- * was synchronized to the system clock.
- *
- * total The total slowdown of the test loop relative
- * to the speed measured at calibration time.
- *
- * The total time is the most interesting, since it reflects
- * the real processor utilization abosorbed by other processes.
- * Proper use of the other two numbers is left as a problem
- * for the reader.
- *
- * WARNINGS
- * CPU is astoundingly inaccurate in systems with different
- * speed memories. In some systems (eg i386 with 16 bit
- * memory on the AT bus) it is not uncommon for calibration
- * runs to vary by a factor of 2 or more. There is no
- * solution but to change the memory or find another machine.
- *
- * The order of parameters 2 & 3 on setvbuf() vary from
- * system, and are even inconsistent between the manuals
- * and the libraries on stock system V.2. You are wise
- * to check the order of the parameters on your system and
- * set the SETVBUF #define accordingly.
- */
-
- #if !defined(lint)
- char whatstring[] = "@(#)cpu.c 3.1 9/22/89" ;
- #endif
-
- #if sun
- #define BSD 1
- #endif
-
- #if BSD
- # include <sys/types.h>
- # include <sys/time.h>
- # include <sys/resource.h>
- #else
- # include <sys/types.h>
- # include <sys/times.h>
- # include <sys/param.h>
- #endif
-
- #include <signal.h>
- #include <ctype.h>
- #include <stdio.h>
-
- #define uchar unsigned char
- #define ushort unsigned short
- #define ulong unsigned long
-
- extern char *optarg ;
- extern int optind ;
-
- extern char *ttyname() ;
- extern long atol() ;
- extern void (*signal())() ;
- extern unsigned sleep() ;
-
- #if BSD
- #else
- extern unsigned alarm() ;
- extern void exit() ;
- extern void perror() ;
- extern time_t times() ;
- #endif
-
-
- #if BSD
- # define TICS 1000 /* Fractional seconds */
- # define MS(tv) (1000000L / TICS * (tv).tv_sec + (tv).tv_usec / TICS)
- #else
- # define TICS HZ
- #endif
-
- #define CALFILE "/tmp/.cpu"
-
-
- double speed ; /* Speed of the processor running */
- double process ; /* Amount of the machine allocated to us */
-
- int debug ; /* Debug flag */
- int delay ; /* Delay before start */
- int timeout ; /* Alarm occurred flag */
- int interrupt ; /* Got an interrupt */
-
- ulong rep ; /* Repeat count */
-
-
-
- /*******
- * Catch interrupts.
- */
-
- sigalrm()
- {
- timeout = 1 ;
- }
-
- sigint()
- {
- interrupt = 1 ;
- }
-
-
- /*******
- * delay - Routine to chew time.
- */
-
- hog()
- {
- static int a = 1 ;
- static int b = 2 ;
- static int c = 3 ;
-
- a += b ;
- b += c ;
- c += a ;
- }
-
-
- /*******
- * measure - Procedure to measure our access to the CPU.
- */
-
- measure(runtime)
- int runtime ; /* Time period */
- {
- ulong real ;
- ulong sys ;
- ulong user ;
- ulong count ;
-
- #if BSD
- struct timeval tv ;
- struct rusage ru ;
- #else
- struct tms tms ;
- #endif
-
- /*
- * Get real time and system time.
- */
-
- #if BSD
- (void) gettimeofday(&tv, (struct timezone *)0) ;
- real = MS(tv) ;
-
- (void) getrusage(RUSAGE_SELF, &ru) ;
- user = MS(ru.ru_utime) ;
- sys = MS(ru.ru_stime) ;
- #else
- real = times(&tms) ;
- user = tms.tms_utime ;
- sys = tms.tms_stime ;
- #endif
-
- if (debug) (void) fprintf(stderr,"Cpu started\n") ;
-
- timeout = 0 ;
- count = 0 ;
-
- (void) signal(SIGALRM, sigalrm) ;
- (void) alarm((unsigned) runtime) ;
-
- (void) nice(40) ;
-
- while (!timeout && !interrupt)
- {
- hog() ;
- count++ ;
- }
-
- (void) nice(-40) ;
-
- #if BSD
- (void) gettimeofday(&tv, (struct timezone *)0) ;
- real = MS(tv) - real ;
-
- (void) getrusage(RUSAGE_SELF, &ru) ;
- user = MS(ru.ru_utime) - user ;
- sys = MS(ru.ru_stime) - sys ;
- #else
- real = times(&tms) - real ;
- user = tms.tms_utime - user ;
- sys = tms.tms_stime - sys ;
- #endif
-
- process = (double) user / (double) real ;
- speed = user ? (double) count / (double) user : 0.0 ;
-
- if (debug)
- {
- (void) fprintf(stderr,
- "real=%ld, sys=%ld, user=%ld, count=%ld\n",
- real, sys, user, count) ;
- (void) fprintf(stderr, "raw process=%.5f, speed=%.5f\n",
- process, speed) ;
- }
- }
-
-
-
- main(argc, argv)
- int argc ;
- char **argv ;
- {
- double cprocess ;
- double cspeed ;
- int calibrate ;
- int runtime = 30 ;
- int err ;
- int c ;
- FILE *cfile ;
- char iobuf[1024] ;
- char buf[200] ;
-
- #if SETVBUF
- (void) setvbuf(stderr, _IOLBF, iobuf, sizeof(iobuf)) ;
- #else
- (void) setvbuf(stderr, iobuf, _IOLBF, sizeof(iobuf)) ;
- #endif
-
- (void) nice(-40) ;
-
- calibrate = 0 ;
- err = 0 ;
-
- while ((c = getopt(argc, argv, "cdrs:t:")) != -1)
- {
- switch (c)
- {
- case 'c':
- calibrate++ ;
- break ;
-
- case 'd':
- debug++ ;
- break ;
-
- case 'r':
- rep = -1 ;
- break ;
-
- case 's':
- delay = atoi(optarg) ;
- break ;
-
- case 't':
- runtime = atoi(optarg) ;
- break ;
-
- case '?':
- err++ ;
- }
- }
-
- if (err || optind < argc)
- {
- (void) fprintf(stderr,
- "usage: %s [ -cd ] [ -t time ]\n", argv[0]) ;
- exit(2) ;
- }
-
- if (delay) (void) sleep((unsigned) delay) ;
-
- if (calibrate)
- {
- measure(runtime) ;
-
- if ((cfile = fopen(CALFILE, "w")) == 0)
- {
- perror(CALFILE) ;
- exit(1) ;
- }
-
- (void) fprintf(cfile, "%f %f\n", process, speed) ;
-
- (void) fprintf(stderr,
- "Calibrated process=%f, speed=%f\n", process, speed) ;
- }
- else
- {
- if ((cfile = fopen(CALFILE, "r")) == 0)
- {
- perror(CALFILE) ;
- (void) fprintf(stderr,
- "Perhaps you should run \"%s -c\" first.\n", argv[0]) ;
- exit(1) ;
- }
-
- if ( fscanf(cfile, "%lf %lf", &cprocess, &cspeed) != 2
- || cprocess == 0
- || cspeed == 0
- )
- {
- (void) fprintf(stderr,
- "%s file does not contain calibrated speed.\n", CALFILE) ;
- }
-
- if (signal(SIGINT, SIG_IGN) != SIG_IGN)
- (void) signal(SIGINT, sigint) ;
-
- for (;;)
- {
- measure(runtime) ;
-
- #if 0
- process /= cprocess ;
- #endif
- speed /= cspeed ;
-
- if (debug)
- {
- (void) fprintf(stderr, "normalized process=%.5f, speed=%.5f\n",
- process, speed) ;
- }
-
- (void) sprintf(buf,
- "TIME process=%.1f, interrupt=%.1f, total=%.1f\n",
- 100 * (1 - process) * speed,
- 100 * (1 - speed),
- 100 * (1 - process * speed)) ;
-
- (void) write(2, buf, (unsigned) strlen(buf)) ;
-
- if (rep == 0 || interrupt) break ;
-
- rep-- ;
- }
- }
-
- return(0) ;
- }
-