[unix-pc.sources] Calculate load average for the unix-pc

ccs@lazlo.UUCP (Clifford C. Skolnick) (01/15/89)

    While cleaning up the hard disk I ran accross this little ditty awhile
ago.  It is a daemon that runs in the background, takeing very little cpu
time, saveing statistics on system load.  When it receives a message from
the other program provided, it will calculate the load average from the
data it has been collecting and send this back to be printed.
    The code is not pretty, but easy to understand if you know System V IPC
already.  I wrote this as a little experiment and ment to clean it up and
post it, but I never did get motivated to clean it up.  At least I'm
posting it!
    As always, any bug reports or suggestions would be appreciated.  Please
no flames saying lint does not like this code, I already know :-).

					Cliff

#!/bin/sh
# shar:	Shell Archiver  (v1.22)
#
#	Run the following text with /bin/sh to create:
#	  Makefile
#	  la.c
#	  ladaemon.c
#
sed 's/^X//' << 'SHAR_EOF' > Makefile &&
Xall: la ladaemon
X	@echo "type 'make install' to install"
X
Xinstall: la ladaemon
X	cp ladaemon /etc/daemons
X	cp la /usr/local/bin
X
Xladaemon: ladaemon.o
X	ld -s ladaemon.o -o ladaemon /lib/crt0s.o /lib/shlib.ifile
X
Xla: la.o
X	ld -s la.o -o la /lib/crt0s.o /lib/shlib.ifile
X
Xladaemon.o:
X	cc -O -c ladaemon.c
X
Xla.o:
X	cc -O -c la.c
X
X
SHAR_EOF
chmod 0644 Makefile || echo "restore of Makefile fails"
sed 's/^X//' << 'SHAR_EOF' > la.c &&
X
X/*
X**  la.c (C) 1988 by Cliff Skolnick (ccs@lazlo.UUCP)
X**
X**
X**
X**  This program gets the load from the ladaemon program.  This is done via
X**  System V message passing.
X*/
X
X
X#define LOGFILE "/usr/adm/la.log"
X
X#include <sys/types.h>
X#include <stdio.h>
X#include <sys/ipc.h>
X#include <sys/msg.h>
X#include <signal.h>
X
X
Xint kmemfd;
Xlong ipckey;
Xint ipcin;
X
Xmain()
X{
X    int ipcout,time_out();
X    long retid,tbuf;
X    double *dindex;
X
X    struct {
X	long mtype;
X	char mtext[81];
X    } msgp;
X
X    /* key is on the log file */
X    if ((ipckey=ftok(LOGFILE,'l'))==-1) {
X	fprintf(stderr,"la: can\'t get key for %s.\n",LOGFILE);
X	perror("la");
X	exit(1);
X    }
X
X    /* get that message queue for ladaemon */
X    if ((ipcout=msgget(ipckey,0222))==-1) {
X	fprintf(stderr,"la: IPC msgget() failed for write.\n");
X	perror("la");
X	exit(1);
X    }
X
X    /* use the pid as a message queue number for us*/
X    retid=(long) getpid();
X
X    /* make a mail box with that number */
X    if ((ipcin=msgget(retid,0666|IPC_CREAT))==-1) {
X	fprintf(stderr,"la: IPC msgget() failed for read.\n");
X	perror("la");
X	exit(1);
X    }
X
X    /* send a message as to where to what queue to put the data */
X    msgp.mtype=1L;
X    *(long *)msgp.mtext=retid;
X    msgsnd(ipcout,&msgp,sizeof(retid),0);
X
X    /* we'll give ladaemon 5 seconds to respond */
X    signal(SIGALRM,time_out);
X    alarm(5);
X
X    /* keep on going untill a good message is received */
X    while (msgrcv(ipcin,&msgp,sizeof(double)*3,0L,0)<0)
X	sleep(1);
X
X    dindex=(double *)msgp.mtext;
X
X    time(&tbuf);
X    printf ("%24.24s, load = %.2f, %.2f, %.2f\n",ctime(&tbuf),dindex[0],dindex[1],dindex[2]);
X    /* kill our queue */
X    msgctl(ipcin,IPC_RMID,0);
X}
X
Xtime_out()
X{
X    fprintf(stderr,"la: no response from ladaemon.\n");
X    msgctl(ipcin,IPC_RMID,0);
X    exit(1);
X}
SHAR_EOF
chmod 0640 la.c || echo "restore of la.c fails"
sed 's/^X//' << 'SHAR_EOF' > ladaemon.c &&
X/*
X**
X** ladaemon - Program to sample and keep track of system information
X** pertaining to load average every 10 seconds.  The information is
X** processed and sent to user processes upon request using the System V IPC
X** mechanism.
X**
X** Author: Cliff Skolnick (ccs@lazlo.UUCP)
X** (C) 1988
X**
X*/
X
X
X#define LOGFILE "/usr/adm/la.log"
X
X#include <sys/types.h>
X#include <stdio.h>
X#include <a.out.h>
X#undef n_name
X#include <fcntl.h>
X#include <sys/sysinfo.h>
X#include <sys/ipc.h>
X#include <sys/msg.h>
X#include <signal.h>
X
X
Xstruct nlist nl[] = {
X    "sysinfo", 0, 0, 0, 0, 0,
X    "", 0, 0, 0, 0, 0
X};
X
Xint kmemfd;
Xlong ipckey;
Xint logfd;
Xint gotalrm;
Xstruct sysinfo mysys;
X
Xunsigned long listocc[61];
Xunsigned long listque[61];
Xunsigned long cpuidle[61];
X
X
Xmain()
X{
X    int i,savecur();
X
X    /* wake up parent */
X    if (fork()!=0)
X	exit(0);
X
X    /* up priority, speed should be as fast as possible so as to get the
X       information back to the user process before it times out */
X    nice(-40);
X
X    /* flag all entries as un-used */
X    for (i=0;i<61;i++)
X	listocc[i]=-1;
X
X    /* get the address of the sysinfo structure */
X    if (nlist("/unix", nl) == -1) {
X	fprintf(stderr, "ladaemon: unable to perform nlist()\n");
X	perror("ladaemon");
X	exit(1);
X    }
X    if (nl[0].n_value == 0) {
X	fprintf(stderr, "ladaemon: nlist() returned null\n");
X	perror("ladaemon");
X	exit(1);
X    }
X
X    /* make sure /dev/kmem is openable */
X    if ((kmemfd  = open("/dev/kmem", O_RDONLY)) == -1) {
X	fprintf(stderr, "ladaemon: unable open /dev/kmem\n");
X	perror("ladaemon");
X	exit(1);
X    }
X
X    logfd=open(LOGFILE,O_WRONLY|O_CREAT,0644);
X    if (logfd==0 || (ipckey=ftok(LOGFILE,'l'))==-1) {
X	fprintf(stderr,"ladaemon: Problem with key\n");
X	perror("ladaemon");
X	exit(1);
X    }
X    close (0);
X    close (1);
X    close (2);
X    dup(logfd);
X    dup(logfd);
X    dup(logfd);
X    close (logfd);
X    setpgrp();
X
X    savecur();
X    doserve();
X}
X
X
Xdoserve()
X{
X    int savecur();
X    int ipcin,ipcout,i;
X    double la1,la5,la10,*dindex,insload;
X    long retid;
X    struct {
X	long mtype;
X	char mtext[81];
X    } msgp;
X
X    if ((ipcin=msgget(ipckey,0622|IPC_CREAT))==-1) {
X	fprintf(stderr,"ladaemon: IPC msgget() failed for read.\n");
X	perror("ladaemon");
X	exit(1);
X    }
X
X    i=0;
X    while (1) {
X	while (i!=sizeof(retid)) {
X	    i=msgrcv(ipcin,&msgp,sizeof(retid),0L,0);
X	}
X
X	retid=*(long *)msgp.mtext;
X	if ((ipcout=msgget(retid,0644|IPC_CREAT))==-1) {
X	    fprintf(stderr,"ladaemon: IPC msgget() failed for write.\n");
X	    perror("ladaemon");
X	    exit(1);
X	}
X
X	gotalrm=1;
X	while (gotalrm) {
X	    la1=la5=la10=0.0;
X	    gotalrm=0;
X	    for (i=60;i>0;i--) {
X		if (listocc[i]==-1)
X		    continue;
X		insload=(double)(listque[i-1]-listque[i])
X		    /(double)(listocc[i-1]-listocc[i])
X		    -((double)cpuidle[i-1]-(double)cpuidle[i])/600.0;
X		la10+=insload;
X		if (i<31) {
X		    la5+=insload;
X		    if (i<7)
X			la1+=insload;
X		}
X	    }
X	}
X
X	la1/=6.0;
X	la5/=30.0;
X	la10/=60.0;
X
X	dindex=(double *)msgp.mtext;
X	*(dindex++)=la1;
X	*(dindex++)=la5;
X	*(dindex++)=la10;
X	msgp.mtype=1L;
X	msgsnd(ipcout,&msgp,sizeof(double)*3,IPC_NOWAIT);
X    }
X}
X
Xsavecur()
X{
X    int i;
X
X    gotalrm++;
X    if (lseek(kmemfd, nl[0].n_value, 0) != -1 && 
X     read(kmemfd, (char *)&mysys, sizeof(mysys)) != -1) {
X	for (i=60;i>0;i--) {
X	    listque[i]=listque[i-1];
X	    listocc[i]=listocc[i-1];
X	    cpuidle[i]=cpuidle[i-1];
X	}
X	*listque=mysys.runque;
X	*listocc=mysys.runocc;
X	*cpuidle=mysys.cpu[CPU_IDLE];
X    }
X    signal(SIGALRM,savecur);
X    alarm(10);
X}
SHAR_EOF
chmod 0640 ladaemon.c || echo "restore of ladaemon.c fails"
exit 0
-- 
Cliff Skolnick (ccs@lazlo)|  "You told me time makes it easy, but you never
Phone: (716) 427-8046     |   told me time stands still" - Gary Numan
TCP/IP: 44.68.0.195       | ...!rutgers!rochester!ritcv!ritcsh!sabin! lazlo!ccs
  ccs@lazlo.n1dph.ampr.org|                      \!kodak!pcid!gizzmo!/