[comp.unix.xenix] lload for xenix

fischer@utower.UUCP (Axel Fischer) (05/26/89)

In article <30067@conexch.UUCP> sandy@conexch.UUCP (Sandford Zelkovitz) writes:
>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.

Hmmm, I don't think that this one works right.
First of all on my Xenix system you must exclude the line

#include <stropts.h>

I don't have it and I don't need it.
Furtheron poll.h is in sys/poll.h, that means you must change the line:

#include <poll.h>
to
#include <sys/poll.h>

What for a Xenix are you using ? 
Ok, after compiling I have started it. And what has happend ?
The three numbers should show me the load average but I've waited several
minutes and the numbers have gone from at the beginning:

Verbose
(1 3) 0.066114 0.013311 0.004442

to
(1 3) 3.493572 1.354233 0.514

And I was the only user online. Have I done something wrong ? And what is
the meaning of the two numbers in brackets ? (1 3)

Maybe the Program runs only with SCO Xenix 286 well ?

Please clarify my questions.

-Axel

-- 
Domain: fischer%utower@tmpmbx.UUCP   /   fischer%utower%tmpmbx@db@tui6.BITNET
USA:    ...!uunet!pyramid!tmpmbx!utower!fischer
       => Beam me up, Scotty - there is no intelligent life down here. <=
                => No, it's life Jim - but not as we know it! <=

sandy@conexch.UUCP (Sandford Zelkovitz) (05/27/89)

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

ccea3@rivm.UUCP (Adri Verhoef) (05/30/89)

I tried to compile the Load Average Daemon on UNIQ (UNIX) System V.3.0,
but at first it wouldn't let me.  I removed two includes:
/* #include <sys/immu.h>	NON-EXISTENT */
/* #include <sys/region.h>	SYNTAX ERROR (pte_t) */

Then I compiled: "cc lload.c -lm -o lload".
I ran "lload -v".  It stopped after ten seconds, saying
	Could not get address for _buf

I compiled with -DM_I386, although the machine is a microVAX,
as to use _pbuf instead of _buf, and I got
	lseek v: Invalid argument
The belonging call is:
	lseek(kmem, v_p->n_value, 0)
Printing v_p->n_value yields -2147211432.

Any ideas?  Thanks.

br@laura.UUCP (Bodo Rueskamp) (05/30/89)

In article <30067@conexch.UUCP> sandy@conexch.UUCP (Sandford Zelkovitz) writes:
>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.

Diffs for Xenix 286 [ sizeof(int) != sizeof(long) !! ]:


*** lload.c	Tue May 30 12:34:15 1989
--- lload.c.orig	Tue May 30 12:34:20 1989
***************
*** 33,40
  
  
  /*  For Xenix:  compile as follows:  cc -Ox lload.c -lm -lx -o lload   */
- /*  For Xenix 286: compile as follows:
- 		cc -M2e -i -Ox lload.c -lm -lx -o lload		*/
  
  /*  Modified for Xenix by Sanford Zelkovitz    XBBS   714-898-8634     */
  /*  Modified for Xenix 286 by Bodo Rueskamp, <br@unido.uucp>  */

--- 33,38 -----
  
  
  /*  For Xenix:  compile as follows:  cc -Ox lload.c -lm -lx -o lload   */
  
  /*  Modified for Xenix by Sanford Zelkovitz    XBBS   714-898-8634     */
  
***************
*** 37,43
  		cc -M2e -i -Ox lload.c -lm -lx -o lload		*/
  
  /*  Modified for Xenix by Sanford Zelkovitz    XBBS   714-898-8634     */
- /*  Modified for Xenix 286 by Bodo Rueskamp, <br@unido.uucp>  */
  
  #include <fcntl.h>
  #ifdef M_XENIX

--- 35,40 -----
  /*  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
***************
*** 46,52
  #include <nlist.h>
  #endif
  #include <stdio.h>
- #ifndef M_XENIX
  #include <stropts.h>
  #include <poll.h>
  #endif

--- 43,48 -----
  #include <nlist.h>
  #endif
  #include <stdio.h>
  #include <stropts.h>
  #include <poll.h>
  #include <math.h>
***************
*** 49,55
  #ifndef M_XENIX
  #include <stropts.h>
  #include <poll.h>
- #endif
  #include <math.h>
  #include <sys/types.h>
  #include <sys/param.h>

--- 45,50 -----
  #include <stdio.h>
  #include <stropts.h>
  #include <poll.h>
  #include <math.h>
  #include <sys/types.h>
  #include <sys/param.h>
***************
*** 169,175
  	 * Read the 'v' structure every time. It says how
  	 * many procs are used.
  	 */
! 	if (lseek(kmem, (long) v_p->n_value, 0) == -1) {
  	    perror("lseek v");
  	    exit(1);
  	}

--- 164,170 -----
  	 * 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);
  	}
***************
*** 180,186
  	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, (long) proc_p->n_value, 0) == -1) {
  	    perror("lseek proc");
  	    exit(1);
  	}

--- 175,181 -----
  	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);
  	}
***************
*** 233,239
  		   av[0]);
  	write(debug_fd, buff, strlen(buff));
  #endif
! 	(void)nap(sleeping * 1000L);
  	free(p);
      }
  }

--- 228,234 -----
  		   av[0]);
  	write(debug_fd, buff, strlen(buff));
  #endif
! 	(void)nap(sleeping * 1000);
  	free(p);
      }
  }

kevin@iisat.UUCP (Kevin Davies) (05/30/89)

In article <1349@rivm05.UUCP>, ccea3@rivm.UUCP (Adri Verhoef) writes:
> I compiled with -DM_I386, although the machine is a microVAX,
> as to use _pbuf instead of _buf, and I got
> 	lseek v: Invalid argument
> The belonging call is:
> 	lseek(kmem, v_p->n_value, 0)
> Printing v_p->n_value yields -2147211432.
> 
> Any ideas?  Thanks.


There's a couple of lseek's in the program that did this.
The problem is that n_value in the nlist structure is defined as
unsigned int, but the lseek argument has to be a long (since in this
realm int != long).
so,
	lseek(kmem, (long) v_p->n_value,0)

this should do the trick...

-- 
Kevin Davies		International Information Service (IIS)
UUCP:  {uunet,utai,watmath}!dalcs!iisat!kevin
Bitnet/Uucp: kevin@iisat.uucp	 Arpanet: kevin%iisat.uucp@uunet.uu.net

dave@mobile.UUCP (David C. Rein) (06/01/89)

Thank you very much, Lars, for putting lload.c onto the net!!  I just
happened to of been looking for such a program!!  Starting it up in /etc/rc,
and with a small modification, I used it to develop an 'uptime' command
for Xenix (maybe there is already one out there, but, I didn't know about
it).  Anyway, I'd thought that anyone that found a use for lload.c might
alos find a use for uptime.c. 


----------------------- cut here for uptime.c ------------------------


/*							(set ts=4)
	This program will read the information written by the lload.c program,
	and display it in a 'ruptime' format.  The lload.c program was 
	written by Lars Pensj from Myab Gothenburg, Sweden, and was
	distributed in alt.sources.  A modified version for Xenix was
	developed by Sanford Zelkovitz.  The following changes need to be
	made to the lload.c program:

		double av[3] = { 0.0, 0.0, 0.0 };
		--	
		double av[4] = { 0.0, 0.0, 0.0, 0.0 };

		and


	    if (write(loadfile, (char *)av, sizeof av) != sizeof av) {
		perror(argv[0]);
		exit(1);
	    }
		--
		av[3] += sleeping;
	    if (write(loadfile, (char *)av, sizeof av) != sizeof av) {
		perror(argv[0]);
		exit(1);
	    }

	Compile: cc -o uptime uptime.c
	Created on 5/29 by David C. Rein 
			(uunet!ism780c!kodak!gizzmo!lazlo!mobile!dave)
*/

#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <utmp.h>
#include <sys/utsname.h>
#define LOADAV "/etc/loadav"					/* Data filename		*/


main()
{
	double av[4];								/* Load information		*/
	int fd;										/* Information file FD 	*/
	int	minutes, hours;							/* Hours and minutes up	*/
	double days,temp;							/* Days up, and calc temp*/
	struct utmp *tstr;							/* Pointer to utmp struct*/
	int users = 0;								/* Users logged in		*/
	struct utsname name;						/* System nodename struct*/

	if ( (fd = open(LOADAV,O_RDONLY)) < 0 ) {
		perror(LOADAV);							/* Can't open info file	*/
		exit(1);
	}
	if ( read(fd, &av[0], sizeof(av)) != sizeof ( av )) {
		perror("Invalid data file");			/* Bad data in file		*/
		exit( 1 );
	}
	close(fd );
	temp = (double)3600 * (double)24;			/* Calculate constants	*/
	minutes = (int)((int)(av[3] / 60 ) % 60);	/* Calculate minutes	*/
	hours = (int)((int)(av[3] / 3600 ) % 24);	/* Calculate hours		*/
	days = (av[3] / temp);						/* Calculate days		*/
	while ( (tstr = (struct utmp *)getutent()) != NULL ) {
		if ( !(tstr->ut_name[0] == 0 || !strncmp(tstr->ut_name,"LOGIN",5))) {
			users++;							/* If not LOGIN or null 
													username, real user	*/
		}
	}
	if ( uname(&name) < 0 ) {
		perror("Unable to get system name");	/* Can't get system name*/
		exit( 1 );
	}
	printf("%-8.8s  up", name.nodename);		/* Print system name	*/
	if ( (int)days > (int)0 )
		printf("%3d+", (int)days);
	else										/* Print days up		*/
		printf("    ");
	printf("%.2d:%.2d,", hours, minutes);		/* Print hours:mins up	*/
	printf("%4d users,", users);				/* # of logged in users	*/
	printf("  load %4.2f, %4.2f, %4.2f\n",av[0], av[1], av[2]);/*load	*/
}



---
                                                               Dave Rein
----------------------------------\  /-----------------------------------------
UUCP: ..!kodak!gizzmo!lazlo!\      \/   "It just goes to show what you can do 
            mobile!dave            /\         if you're a total psychotic"
Domain: dcr0801@ritcv             /  \           -- Woody Allen
---------------------------------/    \----------------------------------------

sandy@conexch.UUCP (Sandford Zelkovitz) (06/01/89)

In article <96@utower.UUCP>, fischer@utower.UUCP (Axel Fischer) writes:
> In article <30067@conexch.UUCP> sandy@conexch.UUCP (Sandford Zelkovitz) writes:
> >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.
> 
> Hmmm, I don't think that this one works right.
> First of all on my Xenix system you must exclude the line
> #include <stropts.h>
> I don't have it and I don't need it.
> Furtheron poll.h is in sys/poll.h, that means you must change the line:
> #include <poll.h>
> to
> #include <sys/poll.h>
> What for a Xenix are you using ? 
> -Axel
> 



I am running Xenix386 2.3.1 with the 2.3 development system. Yes, I do have
/usr/include/poll.h and /usr/include/stropts.h!!!!! /usr/include/poll.h
just says to include <sys/poll.h> and /usr/include/stropts.h just says
include <sys/stropts.h>. I really don't know why you are missing these files;
however, if I were you, I would call SCO ASAP.
 
Sandy


Sanford <sandy> Zelkovitz    XBBS    714-898-8634
uunet!zardoz!alphacm!sandy
att!hermix!alphacm!sandy

csch@netcs.UUCP (Clemens Schrimpe) (06/01/89)

Ha! Thanks to SCO's freaky developers, the load-average stuff is already
included in SCO 2.3.1!

You'll find the label '_avenrun' in /xenix, which is somewhat declared as
unsigned short avenrun[3].
As far, as I have found out (try looking into the 'w' command), they
use a strange floating-point notation for each value. The integer part
is in the higher 8 bits, while the fractional part is in the lower 8 bits.
(That's how 'w' will diplay 'em)

Anyhow - this is how one of our utilities gets the load average:
(simple collection of various subroutines)

	#include <sys/a.out.h>
	#include <fcntl.h>

	print_average ()
	{
	int	fd;
	struct nlist nl;
	unsigned short loadav[3];

	    if ((fd = open ("/dev/kmem", O_RDONLY)) == -1)
		return;
	    strcpy(nl.n_name, "_avenrun");
	    nlist ("/xenix", &nl);
	    if (nl.n_type == 0 || nl.n_value == 0)
		return;
	    if (lseek (fd, nl.n_value, 0) == -1)
		return;
	    if (read (fd, loadav, sizeof (loadav)) != sizeof (loadav))
		return 0;
	    printf (" %2.2f %2.2f %2.2f\n", (double)loadav[0]/256.,
		(double)loadav[1]/256., (double)loadav[2]/256.);
	}

Any corrections from SCO welcome - but guys: better correct your 'w' too 
then :-)

greeting the whole SCO community on the net,

	Clemens Schrimpe, netCS GmbH Informationstechnik Berlin

PS:
By looking more deeply into the kernel's tables you'll also find a fully
working select() and other fancy stuff in Xenix 2.3.1! (thnx 2 sco)
(even though the PTY's have a minor bug, which will prevent the select()
 from working with them - but this is a fast fix ...)
--
UUCP:		csch@netcs		BITNET:	csch@db0tui6.BITNET
ARPA/NSF:	csch@garp.mit.edu	PSI: PSI%26245300033047::CSCH
PHONE:		+49-30-24 42 37		FAX: +49-30-24 38 00
BTX:		0303325016-0003		TELEX: 186672 net d

tony@ajfcal.UUCP (Tony Field) (06/02/89)

What is a "load average"?      Does lload compute load averages??


-- 
+------------------------------------
|  Tony Field                             ..uunet!utai!calgary!ajfcal!tony
|  Co-Design Information Systems Ltd.
|  Calgary, Alberta, Canada                 voice: (403) 266-3239