lload for xenix

Sandford Zelkovitz sandy at conexch.UUCP
Sat May 27 16:13:07 AEST 1989


Below, is my ported version of lload.c for Xenix. The original code,
by Lars Pensj from Myab Gothenburg, Sweden, was distributed in 
alt.sources.

--------------------------- cut for lload.c ----------------------------


/*
 * Load Average deamon.
 *
 * The load average is updated every constant time interval, and the result
 * written to a file as 3 double values.
 *
 * The load average is for the last 1, 5 and 15 minutes (3 values).
 *
 * A second argument (-v) will set the program in a verbose mode, writing
 * the load average to the standard output and not to the file.
 *
 * Preferably start this process from the inittab. It needs special
 * priviledges to read from /dev/kmem.
 *
 * The following processes are regarded as "runnning":
 *   A process that has the SRUN status (simply running).
 *   A process that is being created (SIDLE).
 *   A process that is being swapped out (SXBRK).
 *   A process that waits for disk I/O.
 *
 * A process is regarded as waiting for disk I/O if it is SSLEEP and
 * has wchan set to a buf in the buffer pool.
 *
 * The sleep is implemented using poll on a stream device, not the
 * more usual sleep() call. Why ?
 * Because you do not want to wake up simultaneosly with other programs
 * doing sleep(), which might give wrong load average.
 * Of course, if you do not have the stream pipe device, use the normal
 * sleep().
 */



/*  For Xenix:  compile as follows:  cc -Ox lload.c -lm -lx -o lload   */

/*  Modified for Xenix by Sanford Zelkovitz    XBBS   714-898-8634     */

#include <fcntl.h>
#ifdef M_XENIX
#include <sys/a.out.h>
#else
#include <nlist.h>
#endif
#include <stdio.h>
#include <stropts.h>
#include <poll.h>
#include <math.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/buf.h>
#ifdef M_XENIX
#include <sys/page.h>
#else
#include <sys/immu.h>
#include <sys/region.h>
#endif
#include <sys/var.h>
#include <sys/proc.h>

/* #define DEBUG */	/* Will append all values in a debug file */

#define LOADAV 		"/etc/loadav"	/* Where to write the load avarge */
#define STREAM_PIPE	"/dev/spx"	/* Used for polling with timeout */

/*
 * You may or may not need the '_' in the following names.
 */

#define VAR_NAME "_v"
#ifdef M_I386
#define BUF_NAME "_pbuf"
#else
#define BUF_NAME "_buf"
#endif
#define PROC_NAME "_proc"

struct nlist nl[] = {
 {VAR_NAME},
 {BUF_NAME},
 {PROC_NAME},
 {0},
};

int loadfile;				/* file descr to result file */
struct proc *p;
struct var v;
int kmem;
struct nlist *v_p, *proc_p, *buf_p;
int size;
int first_buf, last_buf;
int sleeping = 1;			/* Poll frequency in seconds */
int verbose = 0;

double av[3] = { 0.0, 0.0, 0.0 };	/* The loadaverage */
double apa[3];				/* Holding constants */

main(argc, argv)
    char **argv;
{
    int i, n, n_run, n_disk;
#ifdef DEBUG
    int debug_fd;
    char buff[100];
    debug_fd = open("/tmp/loadavdebug", O_CREAT|O_WRONLY);
#endif

    if (argc == 2 && strcmp(argv[1], "-v") == 0) {
	verbose = 1;
	printf("Verbose\n");
    }
    kmem = open("/dev/kmem", 0);
    if (kmem == -1) {
	perror("/dev/kmem");
	exit(1);
    }
    if (!verbose) {
	loadfile = open(LOADAV, 1|O_CREAT,0664);
	if (loadfile == -1) {
	    fprintf(stderr, "%s:", argv[0]);
	    perror(LOADAV);
	    exit(1);
	}
    }
#ifdef M_XENIX

    if (nlist("/xenix", nl) == -1) {
#else
    if (nlist("/unix", nl) == -1) {
#endif
	perror("nlist");
	exit(1);
    }
    for (i=0; nl[i].n_name; i++) {
#ifdef M_XENIX
	if(nl[i].n_name[0] == '\0')
		break;
#endif
#ifdef DEBUG
	fprintf(stderr, "nl[%d] = %s\n", i, nl[i].n_name);
#endif
	if (nl[i].n_value == 0) {
	    fprintf(stderr, "Could not get address for %s\n", nl[i].n_name);
	    exit(1);
	}
	if (strcmp(nl[i].n_name, VAR_NAME) == 0)
	    v_p = &nl[i];
	if (strcmp(nl[i].n_name, PROC_NAME) == 0)
	    proc_p = &nl[i];
	if (strcmp(nl[i].n_name, BUF_NAME) == 0)
	    buf_p = &nl[i];
    }
    /*
     * Setup the constants used for computing load average.
     */
    apa[0] = exp(-sleeping/60.0);
    apa[1] = exp(-sleeping/300.0);
    apa[2] = exp(-sleeping/900.0);
    /*
     * Start looping
     */
    while(1) {
	/*
	 * Read the 'v' structure every time. It says how
	 * many procs are used.
	 */
	if (lseek(kmem, v_p->n_value, 0) == -1) {
	    perror("lseek v");
	    exit(1);
	}
	if (read(kmem, &v, sizeof v) == -1) {
	    perror("read v");
	    exit(1);
	}
	size = (struct proc *)v.ve_proc - (struct proc *)proc_p->n_value;
	first_buf = buf_p->n_value;
	last_buf = first_buf + v.v_buf * sizeof (struct buf);
	if (lseek(kmem, proc_p->n_value, 0) == -1) {
	    perror("lseek proc");
	    exit(1);
	}
	p = (struct proc *)malloc(size * sizeof (struct proc));
	if (p == 0) {
	    fprintf(stderr, "Could not malloc %d bytes\n",
		    size * sizeof (struct proc));
	    exit(1);
	}
	n = read(kmem, p, size * sizeof (struct proc));
	if (n != size * sizeof (struct proc)) {
	    if (n == -1) {
		perror("read procs");
		exit(1);
	    }
	    fprintf(stderr, "Could only read %d (%d) procs\n",
		    n, size);
	    size = n / sizeof (struct proc);
	}
	n_run = 0;
	n_disk = 0;
	for (i=0; i<size; i++) {
	    if (p[i].p_stat == SRUN || p[i].p_stat == SIDL ||
		p[i].p_stat == SXBRK)
		n_run++;
	    else if (p[i].p_stat == SSLEEP &&
		     (unsigned int)p[i].p_wchan >= first_buf &&
		     (unsigned int)p[i].p_wchan < last_buf)
		n_disk++;
	}
	/*
	 * Update the load average using a decay filter.
	 */
	for (i = 0; i < 3; i++)
	    av[i] = apa[i] * av[i] + (n_run + n_disk) * (1.0 - apa[i]);
	if (!verbose) {
	    if (lseek(loadfile, 0L, 0) == -1) {
		fprintf(stderr, "Couldn't seek in %s\n", LOADAV);
		exit(1);
	    }
	    if (write(loadfile, (char *)av, sizeof av) != sizeof av) {
		perror(argv[0]);
		exit(1);
	    }
	} else
	    printf("(%d %d) %f %f %f\n", n_run, n_disk,
		   av[0], av[1], av[2]);
#ifdef DEBUG
	sprintf(buff, "(%d %d) %4.2f\n", n_run, n_disk,
		   av[0]);
	write(debug_fd, buff, strlen(buff));
#endif
	(void)nap(sleeping * 1000);
	free(p);
    }
}
#ifndef M_XENIX

/*
 * Use a stream pipe to implement a sleep.
 * We have a stream pipe for ourselves, so we know noone will write
 * on it.
 */
nap(milli) {
    static int fd = 0;
    static struct pollfd pollfd;

    if (fd == 0) {
	fd = open(STREAM_PIPE, 0);
	if (fd == -1) {
	    perror(STREAM_PIPE);
	    exit(1);
	}
	pollfd.fd = fd;
	pollfd.events = POLLIN;
    }
    if (poll(&pollfd, 1, milli) == -1) {
	perror("nap: poll");
	exit(1);
    }
    if (pollfd.revents != 0) {
	fprintf(stderr, "nap: poll: got something\n");
	exit(1);
    }
}
#endif



More information about the Comp.unix.xenix mailing list