home *** CD-ROM | disk | FTP | other *** search
- From allbery@ncoast.UUCP Tue Feb 10 20:53:27 1987
- Path: beno!seismo!columbia!rutgers!clyde!cbatt!cwruecmp!hal!ncoast!allbery
- From: allbery@ncoast.UUCP (Brandon S. Allbery)
- Newsgroups: net.sources
- Subject: A load average daemon for System V.2
- Message-ID: <2046@ncoast.UUCP>
- Date: 11 Feb 87 01:53:27 GMT
- Reply-To: allbery@ncoast.UUCP (Brandon S. Allbery)
- Distribution: world
- Organization: Cleveland Public Access UNIX, Cleveland, OH
- Lines: 395
-
- +---------------
- | Can anyone give me a lead on how one can determine the system load
- | on UNIX System V Release 2? (In particular, this is running on a
- | 3B2.) It doesn't have to be as elaborate as the 1,5,15 minute averages
- | available under Berkeley UNIX, but I need something that could be used
- | to get rough estimates of current busy-ness of the system. (This
- | would then by called by processes on other network hosts to find the
- | least-used machine to give a job to.)
- +---------------
-
- The original form of these routines is From: budd@bu-cs.BU.EDU (Philip Budne).
- I include his README below.
-
- +---------------
- | Here is a program I wrote to generate a load average for USG, we run
- | it on our 3b2s and our 3b5. Of course you might be better off putting
- | it into the kernal clock.c routines where the sysinf data is generated.
- |
- | This is a real T(w)enex (also BSD) style load average, the sysinf
- | structure (shockingly) provides exactly the needed information.
- |
- | The data is stored in a BSD style rwhod packet/file.
- +---------------
-
- I have modified this program: if RWHOD is defined, it performs its original
- function of forging rwhod packets; undef'ed, it creates a shm segment whose
- key is ftok("/unix", 'a') and constantly updates three (double)'s stored in
- it. The non-RWHOD stuff doesn't need the network hacks the original needed.
-
- It is designed to be run as a ((terminology? daemon: dragon)). We typically
- start it in /etc/rc. BTW, in case you do telinit s/telinit 2, you should
- ipcrm the shm segment before starting avenrun.
-
- WARNING: The file below is NOT a ``shar'' file!!!
-
- ++Brandon
- -----------------------cut, bend, fold, spindle, mutilate---------------------
- /*
- * avenrun.c -- calculate System V load average, post into shm segment
- * Brandon S. Allbery, TDI
- * Based on:
- * ldavg.c -- compute load averages for System V
- * Phil Budne @ Boston U / DSG
- *
- * Forges BSD 4.2 rwhod packets containing system load averages
- *
- * My version (no #define RWHOD) uses a shm segment, ftok("/unix", 'a'),
- * containing three (double)'s, for the 1, 5, and 15 minute load averages.
- */
-
- # include <sys/types.h> /* system types */
- # include <sys/sysinfo.h> /* sysinfo structure */
- # include <sys/utsname.h> /* for uname(2) */
- # include <sys/stat.h> /* for stat(2) */
- # include <sys/param.h> /* for HZ */
- # include <stdio.h>
- # include <nlist.h>
- # include <time.h>
- # include <math.h>
- # include <utmp.h>
- # include <fcntl.h>
- #ifdef RWHOD
- # include "rwhod.h" /* (from BSD) */
- #else SHM
- # include <sys/ipc.h>
- # include <sys/shm.h>
- #endif RWHOD
-
- /* # define DEBUG /**/
- #ifdef RWHOD
- # define UDP 1
- # define DSK 1
- # define PMUL 100
-
- # if UDP
- # include "netdb.h"
- unsigned short port = 513;
- unsigned long ipaddr;
- # endif
- #endif RWHOD
-
- extern struct utmp *getutent();
-
- # define SYSTEM "/unix"
- # define KMEM "/dev/kmem"
-
- struct nlist nl[] = {
- # define NL_SYSINFO 0
- { "_sysinfo" }, /* 0 */
- # define NL_LBOLT 1
- { "_lbolt" }, /* 1 */
- { 0 }
- };
-
- #ifdef RWHOD
- struct whod proto;
- struct utsname utsn;
- char whopacket[100];
- #else SHM
- key_t aven_key;
- int aven_shm;
- double *aven_seg;
- #endif RWHOD
- int fd, memfd;
-
- char *system = SYSTEM;
- char *kmem = KMEM;
- char *argv0;
-
- main(argc, argv)
- int argc;
- char *argv[];
- {
- switch (fork()) {
- case -1:
- perror("fork");
- exit(1);
- case 0:
- break;
- default:
- exit(0);
- }
- argv0 = argv[0];
- #ifdef RWHOD
- uname(&utsn); /* get system names */
- #endif RWHOD
- setpgrp(); /* create own pgrp */
- init_nlist(); /* get name values, open kmem */
- init_packet(); /* initialize packet prototype */
- doit(); /* never returns */
- } /* main */
-
- init_nlist() {
- nlist(system, nl); /* get system values */
-
- if(nl[NL_SYSINFO].n_value == 0) {
- fprintf(stderr, "%s: can't find sysinf structure\n", argv0);
- exit(1);
- } /* no value */
-
- if ((memfd = open(kmem, O_RDONLY)) < 0) {
- fprintf(stderr, "%s: no mem\n", argv0);
- exit(1);
- } /* could not open kmem */
-
- } /* init_nlist */
-
- # define PERIOD 5 /* sample period (in seconds) */
- # define INTERVAL1 60 /* average interval 1 (in seconds) */
- # define INTERVAL2 (5*60) /* average interval 2 (in seconds) */
- # define INTERVAL3 (15*60) /* average interval 3 (in seconds) */
- # define PACKINTERVAL 30 /* interval for make_packet */
-
- doit() {
- struct sysinfo sinf;
- int packt = 0;
- long occ, que, nocc, nque, n, c;
- double avg1, avg2, avg3, new;
- double exp1, exp2, exp3;
-
- exp1 = exp( - ((double) PERIOD) / INTERVAL1 );
- exp2 = exp( - ((double) PERIOD) / INTERVAL2 );
- exp3 = exp( - ((double) PERIOD) / INTERVAL3 );
-
- getsysinf(&sinf); /* prime the pump */
- occ = sinf.runocc; /* number of samples */
- que = sinf.runque; /* run queue summation */
-
- avg1 = avg2 = avg3 = ((double) que) / occ;
-
- for( ; ; ) {
- if( --packt < 0 ) {
- #ifdef RWHOD
- make_packet((int) (avg1 * PMUL),
- (int) (avg2 * PMUL),
- (int) (avg3 * PMUL));
- #else SHM
- make_packet(avg1, avg2, avg3);
- #endif RWHOD
- packt = PACKINTERVAL / PERIOD;
- } /* packet time */
-
- /* printf("runque: %ld runocc: %ld\n", que, occ ); /**/
-
- sleep(PERIOD);
- getsysinf(&sinf); /* get new info */
- nocc = sinf.runocc;
- nque = sinf.runque;
-
- n = nocc - occ; /* get number of times updated */
- if( n <= 0 ) continue;
- c = nque - que - n; /* get number of runners w/o us */
- if( c < 0 ) c = 0; /* mumble! */
-
- new = ((double) c ) / n; /* new instantaneous avg */
-
- /************************************************/
- /* The following formwla is used to achieve */
- /* exponential decay of old measurements: */
- /* avgN = avgN * expN + new * (1 - expN) */
- /* */
- /* However, the factorized forms below */
- /* require fewer floating point operations. */
- /************************************************/
-
- avg1 = ((avg1 - new) * exp1) + new;
- avg2 = ((avg2 - new) * exp2) + new;
- avg3 = ((avg3 - new) * exp3) + new;
-
- occ = nocc;
- que = nque;
-
- } /* for ever */
- } /* doit */
-
- getsysinf(s)
- struct sysinfo *s;
- {
- l_lseek(memfd, (long)nl[NL_SYSINFO].n_value, 0);
- r_read(memfd, (char *)s, sizeof(struct sysinfo));
- }
-
- /* lseek with error checking */
- l_lseek(fd, offset, whence)
- int fd, whence;
- long offset;
- {
- if (lseek(fd, offset, whence) == -1) {
- fprintf(stderr, "%s: error on lseek\n", argv0);
- exit(1);
- }
- }
-
- /* read with error checking */
- r_read (fd, buf, nbytes)
- int fd, nbytes;
- char *buf;
- {
- if (read(fd, buf, nbytes) != nbytes) {
- fprintf(stderr, "%s: error on read\n", argv0);
- exit(1);
- }
- }
-
- init_packet() {
- #ifdef RWHOD
- time_t boothz;
- # if UDP
- struct hostent *he;
-
- he = gethostbyname( "localnet" );
- if( he == NULL || he->h_addr == 0 ) {
- fprintf(stderr, "no address: localnet\n");
- exit( 1 );
- }
- ipaddr = he->h_addr;
- # endif
- # if DSK
- sprintf(whopacket, "/usr/spool/rwho/whod.%s", utsn.nodename);
- # endif
- memset(&proto, '\0', sizeof proto); /* clear proto packet */
-
- strncat(proto.wd_hostname, utsn.nodename, 9); /* at most 9, add null */
- proto.wd_vers = WHODVERSION;
- proto.wd_type = WHODTYPE_STATUS;
-
- l_lseek(memfd, (long)nl[NL_LBOLT].n_value, 0);
- r_read(memfd, (char *)&boothz, sizeof( boothz ) );
- proto.wd_boottime = time(0) - (boothz / HZ);
- #else SHM
- if ((aven_key = ftok(SYSTEM, 'a')) == (key_t) -1) {
- perror(SYSTEM);
- exit(1);
- }
- if ((aven_shm = shmget(aven_key, 3 * sizeof (double), IPC_CREAT|IPC_EXCL|0644)) < 0) {
- perror("shmget");
- exit(1);
- }
- if ((int) (aven_seg = (double *) shmat(aven_shm, (char *) 0, 0)) == -1) {
- perror("shmat");
- if (shmdt((char *) aven_seg) == -1)
- perror("shmdt");
- if (shmctl(aven_shm, IPC_RMID, (struct shmid_ds *) 0) < 0)
- perror("shmctl(IPC_RMID)");
- exit(1);
- }
- #endif RWHOD
-
- } /* init_packet */
-
- make_packet(iavg1, iavg2, iavg3)
- #ifdef RWHOD
- long iavg1, iavg2, iavg3;
- #else SHM
- double iavg1, iavg2, iavg3;
- #endif RWHOD
- {
- #ifdef RWHOD
- static struct whod packet; /* local packet copy */
- register struct whoent *wep; /* pointer to packet whoent */
- register struct utmp *utp; /* return from getutent */
- int whof, cc; /* output file, char count */
-
- packet = proto; /* copy proto packet */
- time(&packet.wd_sendtime);
- time(&packet.wd_recvtime); /* forge this !! */
- packet.wd_loadav[0] = iavg1;
- packet.wd_loadav[1] = iavg2;
- packet.wd_loadav[2] = iavg3;
-
- setutent(); /* open utmp file */
- wep = &packet.wd_we[0]; /* get pointer to first user in pkt */
-
- while( (utp = getutent()) != NULL ) {
- if( (utp->ut_type == USER_PROCESS) && utp->ut_user[0]) {
- strncpy(wep->we_utmp.out_line, utp->ut_id, 4);
- wep->we_utmp.out_line[4] = '\0';
-
- strncpy(wep->we_utmp.out_name, utp->ut_user, 8);
-
- wep->we_utmp.out_time = utp->ut_time;
-
- wep->we_idle = idletime(utp);
- wep++; /* bump packet pointer */
- } /* user process */
- } /* while */
- endutent();
-
- # if DSK
- whof = creat(whopacket, 0644); /* open packt file */
- if( whof >= 0 ) {
- cc = (char *)wep - (char *)&packet;
- if( write(whof, (char *)&packet, cc) != cc )
- perror("write failed");
- close(whof);
- } /* file opened */
- else perror(whopacket);
- # endif
- # if UDP
- cc = (char *)wep - (char *)&packet;
- udpsend( (char *)&packet, cc, ipaddr, port, port, 1);
- # endif
- # ifdef DEBUG
- fprintf(stderr, "wrote packet (%d)\n", cc);
- fflush(stderr);
- # endif
- #else SHM
- aven_seg[0] = iavg1;
- aven_seg[1] = iavg2;
- aven_seg[2] = iavg3;
- #endif RWHOD
- } /* make_packet */
-
- #ifdef RWHOD
- idletime(up)
- struct utmp *up;
- {
- register int i;
- register char *cp, *dp;
- char ttyname[10];
- struct stat buf;
- time_t now;
-
- cp = "/dev/";
- dp = ttyname;
-
- while( *cp != '\0' ) /* copy "/dev/" */
- *dp++ = *cp++;
-
- cp = up->ut_line; /* get line name */
- if( *cp == 's' ) /* starts with an 's'? (sxtnnn) */
- *dp++ = 'v'; /* insert a 'v' */
-
- for( i = 0; i < 8; i++ ) /* copy line name */
- if( (*dp++ = *cp++) == '\0' ) break; /* or until null */
-
- if( stat(ttyname, &buf) != 0 ) /* get file status */
- return( 0 );
-
- time(&now); /* get current time */
- i = now - buf.st_atime; /* get differnce from last acces */
- return( i ); /* return idle time */
- } /* idletime */
- #endif RWHOD
- ------------------------------------------------------------------------------
-
-
- --
- ++Brandon (Resident Elf @ ncoast.UUCP)
- ____ ______________
- / \ / __ __ __ \ Brandon S. Allbery <backbone>!ncoast!allbery
- ___ | /__> / \ / \ aXcess Co., Consulting ncoast!allbery@Case.CSNET
- / \ | | `--, `--, 6615 Center St. #A1-105 (...@relay.CS.NET)
- | | \__/ \__/ \__/ Mentor, OH 44060-4101
- \____/ \______________/ +1 216 974 9210
-
-
-