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