home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / net / sysv.loadav < prev    next >
Internet Message Format  |  1987-02-11  |  11KB

  1. From allbery@ncoast.UUCP Tue Feb 10 20:53:27 1987
  2. Path: beno!seismo!columbia!rutgers!clyde!cbatt!cwruecmp!hal!ncoast!allbery
  3. From: allbery@ncoast.UUCP (Brandon S. Allbery)
  4. Newsgroups: net.sources
  5. Subject: A load average daemon for System V.2
  6. Message-ID: <2046@ncoast.UUCP>
  7. Date: 11 Feb 87 01:53:27 GMT
  8. Reply-To: allbery@ncoast.UUCP (Brandon S. Allbery)
  9. Distribution: world
  10. Organization: Cleveland Public Access UNIX, Cleveland, OH
  11. Lines: 395
  12.  
  13. +---------------
  14. | Can anyone give me a lead on how one can determine the system load
  15. | on UNIX System V Release 2? (In particular, this is running on a
  16. | 3B2.) It doesn't have to be as elaborate as the 1,5,15 minute averages
  17. | available under Berkeley UNIX, but I need something that could be used
  18. | to get rough estimates of current busy-ness of the system. (This 
  19. | would then by called by processes on other network hosts to find the
  20. | least-used machine to give a job to.)
  21. +---------------    
  22.     
  23. The original form of these routines is From: budd@bu-cs.BU.EDU (Philip Budne).
  24. I include his README below.
  25.  
  26. +---------------
  27. | Here is a program I wrote to generate a load average for USG, we run
  28. | it on our 3b2s and our 3b5.  Of course you might be better off putting
  29. | it into the kernal clock.c routines where the sysinf data is generated.
  30. | This is a real T(w)enex (also BSD) style load average, the sysinf
  31. | structure (shockingly) provides exactly the needed information.
  32. | The data is stored in a BSD style rwhod packet/file.
  33. +---------------
  34.  
  35. I have modified this program:  if RWHOD is defined, it performs its original
  36. function of forging rwhod packets; undef'ed, it creates a shm segment whose
  37. key is ftok("/unix", 'a') and constantly updates three (double)'s stored in
  38. it.  The non-RWHOD stuff doesn't need the network hacks the original needed.
  39.  
  40. It is designed to be run as a ((terminology? daemon: dragon)).  We typically
  41. start it in /etc/rc.  BTW, in case you do telinit s/telinit 2, you should
  42. ipcrm the shm segment before starting avenrun.
  43.  
  44. WARNING:  The file below is NOT a ``shar'' file!!!
  45.  
  46. ++Brandon
  47. -----------------------cut, bend, fold, spindle, mutilate---------------------
  48. /*
  49.  * avenrun.c -- calculate System V load average, post into shm segment
  50.  * Brandon S. Allbery, TDI
  51.  * Based on:
  52.  * ldavg.c -- compute load averages for System V
  53.  * Phil Budne @ Boston U / DSG
  54.  *
  55.  * Forges BSD 4.2 rwhod packets containing system load averages
  56.  *
  57.  * My version (no #define RWHOD) uses a shm segment, ftok("/unix", 'a'),
  58.  * containing three (double)'s, for the 1, 5, and 15 minute load averages.
  59.  */
  60.  
  61. # include <sys/types.h>            /* system types */
  62. # include <sys/sysinfo.h>        /* sysinfo structure */
  63. # include <sys/utsname.h>        /* for uname(2) */
  64. # include <sys/stat.h>            /* for stat(2) */
  65. # include <sys/param.h>            /* for HZ */
  66. # include <stdio.h>
  67. # include <nlist.h>
  68. # include <time.h>
  69. # include <math.h>
  70. # include <utmp.h>
  71. # include <fcntl.h>
  72. #ifdef RWHOD
  73. # include "rwhod.h"            /* (from BSD) */
  74. #else  SHM
  75. # include <sys/ipc.h>
  76. # include <sys/shm.h>
  77. #endif RWHOD
  78.  
  79. /* # define DEBUG /**/
  80. #ifdef RWHOD
  81. # define UDP 1
  82. # define DSK 1
  83. # define PMUL 100
  84.  
  85. # if UDP
  86. # include "netdb.h"
  87. unsigned short port = 513;
  88. unsigned long ipaddr;
  89. # endif
  90. #endif RWHOD
  91.  
  92. extern struct utmp *getutent();
  93.  
  94. # define SYSTEM "/unix"
  95. # define KMEM "/dev/kmem"
  96.  
  97. struct nlist nl[] = {
  98. # define NL_SYSINFO 0
  99.         { "_sysinfo" },            /* 0 */
  100. # define NL_LBOLT 1
  101.     { "_lbolt" },            /* 1 */
  102.         { 0 }
  103. };
  104.  
  105. #ifdef RWHOD
  106. struct whod proto;
  107. struct utsname utsn;
  108. char whopacket[100];
  109. #else  SHM
  110. key_t aven_key;
  111. int aven_shm;
  112. double *aven_seg;
  113. #endif RWHOD
  114. int fd, memfd;
  115.  
  116. char *system = SYSTEM;
  117. char *kmem = KMEM;
  118. char *argv0;
  119.  
  120. main(argc, argv)
  121. int  argc;
  122. char *argv[];
  123. {
  124.     switch (fork()) {
  125.     case -1:
  126.         perror("fork");
  127.         exit(1);
  128.     case 0:
  129.         break;
  130.     default:
  131.         exit(0);
  132.     }
  133.     argv0 = argv[0];
  134. #ifdef RWHOD
  135.     uname(&utsn);            /* get system names */
  136. #endif RWHOD
  137.     setpgrp();            /* create own pgrp */
  138.     init_nlist();            /* get name values, open kmem */
  139.     init_packet();            /* initialize packet prototype */
  140.     doit();                /* never returns */
  141. } /* main */
  142.  
  143. init_nlist() {
  144.     nlist(system, nl);        /* get system values */
  145.  
  146.         if(nl[NL_SYSINFO].n_value == 0) {
  147.                 fprintf(stderr, "%s: can't find sysinf structure\n", argv0);
  148.                 exit(1);
  149.         } /* no value */
  150.  
  151.     if ((memfd = open(kmem, O_RDONLY)) < 0) {
  152.         fprintf(stderr, "%s: no mem\n", argv0);
  153.         exit(1);
  154.     } /* could not open kmem */
  155.  
  156. } /* init_nlist */
  157.  
  158. # define PERIOD 5            /* sample period (in seconds) */
  159. # define INTERVAL1 60            /* average interval 1 (in seconds) */
  160. # define INTERVAL2 (5*60)        /* average interval 2 (in seconds) */
  161. # define INTERVAL3 (15*60)        /* average interval 3 (in seconds) */
  162. # define PACKINTERVAL 30        /* interval for make_packet */
  163.  
  164. doit() {
  165.     struct sysinfo sinf;
  166.     int packt = 0;
  167.     long occ, que, nocc, nque, n, c;
  168.     double avg1, avg2, avg3, new;
  169.     double exp1, exp2, exp3;
  170.  
  171.     exp1 = exp( - ((double) PERIOD) / INTERVAL1 );
  172.     exp2 = exp( - ((double) PERIOD) / INTERVAL2 );
  173.     exp3 = exp( - ((double) PERIOD) / INTERVAL3 );
  174.  
  175.     getsysinf(&sinf);        /* prime the pump */
  176.     occ = sinf.runocc;        /* number of samples */
  177.     que = sinf.runque;        /* run queue summation */
  178.  
  179.     avg1 = avg2 = avg3 = ((double) que) / occ;
  180.  
  181.     for( ; ; ) {
  182.         if( --packt < 0 ) {
  183. #ifdef RWHOD
  184.             make_packet((int) (avg1 * PMUL),
  185.                     (int) (avg2 * PMUL),
  186.                     (int) (avg3 * PMUL));
  187. #else  SHM
  188.             make_packet(avg1, avg2, avg3);
  189. #endif RWHOD
  190.             packt = PACKINTERVAL / PERIOD;
  191.         } /* packet time */
  192.  
  193. /*        printf("runque: %ld  runocc: %ld\n", que, occ ); /**/
  194.  
  195.         sleep(PERIOD);
  196.         getsysinf(&sinf);    /* get new info */
  197.         nocc = sinf.runocc;
  198.         nque = sinf.runque;
  199.  
  200.         n = nocc - occ;        /* get number of times updated */
  201.         if( n <= 0 ) continue;
  202.         c = nque - que - n;    /* get number of runners w/o us */
  203.         if( c < 0 ) c = 0;    /* mumble! */
  204.  
  205.         new = ((double) c ) / n; /* new instantaneous avg */
  206.  
  207.         /************************************************/
  208.         /*   The following formwla is used to achieve   */
  209.         /*   exponential decay of old measurements:    */
  210.         /*    avgN = avgN * expN  +  new * (1 - expN)    */
  211.         /*                        */
  212.         /*   However, the factorized forms below    */
  213.         /*   require fewer floating point operations.    */
  214.         /************************************************/
  215.  
  216.         avg1 = ((avg1 - new) * exp1) + new;
  217.         avg2 = ((avg2 - new) * exp2) + new;
  218.         avg3 = ((avg3 - new) * exp3) + new;
  219.  
  220.         occ = nocc;
  221.         que = nque;
  222.  
  223.     } /* for ever */
  224. } /* doit */
  225.  
  226. getsysinf(s)
  227. struct sysinfo *s;
  228. {
  229.     l_lseek(memfd, (long)nl[NL_SYSINFO].n_value, 0);
  230.     r_read(memfd, (char *)s, sizeof(struct sysinfo));
  231. }
  232.  
  233. /* lseek with error checking */
  234. l_lseek(fd, offset, whence)
  235. int fd, whence;
  236. long    offset;
  237. {
  238.     if (lseek(fd, offset, whence) == -1) {
  239.         fprintf(stderr, "%s: error on lseek\n", argv0);
  240.         exit(1);
  241.     }
  242. }
  243.  
  244. /* read with error checking */
  245. r_read (fd, buf, nbytes)
  246. int    fd, nbytes;
  247. char    *buf;
  248. {
  249.     if (read(fd, buf, nbytes) != nbytes) {
  250.         fprintf(stderr, "%s: error on read\n", argv0);
  251.         exit(1);
  252.     }
  253. }
  254.  
  255. init_packet() {
  256. #ifdef RWHOD
  257.     time_t boothz;
  258. # if UDP
  259.     struct hostent *he;
  260.  
  261.     he = gethostbyname( "localnet" );
  262.     if( he == NULL || he->h_addr == 0 ) {
  263.         fprintf(stderr, "no address: localnet\n");
  264.         exit( 1 );
  265.     }
  266.     ipaddr = he->h_addr;
  267. # endif
  268. # if DSK
  269.     sprintf(whopacket, "/usr/spool/rwho/whod.%s", utsn.nodename);
  270. # endif
  271.     memset(&proto, '\0', sizeof proto);    /* clear proto packet */
  272.  
  273.     strncat(proto.wd_hostname, utsn.nodename, 9); /* at most 9, add null */
  274.     proto.wd_vers = WHODVERSION;
  275.     proto.wd_type = WHODTYPE_STATUS;
  276.  
  277.     l_lseek(memfd, (long)nl[NL_LBOLT].n_value, 0);
  278.     r_read(memfd, (char *)&boothz, sizeof( boothz ) );
  279.     proto.wd_boottime = time(0) - (boothz / HZ);
  280. #else  SHM
  281.     if ((aven_key = ftok(SYSTEM, 'a')) == (key_t) -1) {
  282.         perror(SYSTEM);
  283.         exit(1);
  284.     }
  285.     if ((aven_shm = shmget(aven_key, 3 * sizeof (double), IPC_CREAT|IPC_EXCL|0644)) < 0) {
  286.         perror("shmget");
  287.         exit(1);
  288.     }
  289.     if ((int) (aven_seg = (double *) shmat(aven_shm, (char *) 0, 0)) == -1) {
  290.         perror("shmat");
  291.         if (shmdt((char *) aven_seg) == -1)
  292.             perror("shmdt");
  293.         if (shmctl(aven_shm, IPC_RMID, (struct shmid_ds *) 0) < 0)
  294.             perror("shmctl(IPC_RMID)");
  295.         exit(1);
  296.     }
  297. #endif RWHOD
  298.     
  299. } /* init_packet */
  300.  
  301. make_packet(iavg1, iavg2, iavg3)
  302. #ifdef RWHOD
  303. long iavg1, iavg2, iavg3;
  304. #else  SHM
  305. double iavg1, iavg2, iavg3;
  306. #endif RWHOD
  307. {
  308. #ifdef RWHOD
  309.     static struct whod packet;    /* local packet copy */
  310.     register struct whoent *wep;    /* pointer to packet whoent */
  311.     register struct utmp *utp;    /* return from getutent */
  312.     int whof, cc;            /* output file, char count */
  313.  
  314.     packet = proto;            /* copy proto packet */
  315.     time(&packet.wd_sendtime);
  316.     time(&packet.wd_recvtime);    /* forge this !! */
  317.     packet.wd_loadav[0] = iavg1;
  318.     packet.wd_loadav[1] = iavg2;
  319.     packet.wd_loadav[2] = iavg3;
  320.  
  321.     setutent();            /* open utmp file */
  322.     wep = &packet.wd_we[0];        /* get pointer to first user in pkt */
  323.  
  324.     while( (utp = getutent()) != NULL ) {
  325.         if( (utp->ut_type == USER_PROCESS) && utp->ut_user[0]) {
  326.         strncpy(wep->we_utmp.out_line, utp->ut_id, 4);
  327.         wep->we_utmp.out_line[4] = '\0';
  328.  
  329.         strncpy(wep->we_utmp.out_name, utp->ut_user, 8);
  330.  
  331.         wep->we_utmp.out_time = utp->ut_time;
  332.  
  333.         wep->we_idle = idletime(utp);
  334.         wep++;            /* bump packet pointer */
  335.         } /* user process */
  336.     } /* while */
  337.     endutent();
  338.  
  339. # if DSK
  340.     whof = creat(whopacket, 0644);    /* open packt file */
  341.     if( whof >= 0 ) {
  342.         cc = (char *)wep - (char *)&packet;
  343.         if( write(whof, (char *)&packet, cc) != cc )
  344.             perror("write failed");
  345.         close(whof);
  346.     } /* file opened */
  347.     else perror(whopacket);
  348. # endif
  349. # if UDP
  350.     cc = (char *)wep - (char *)&packet;
  351.     udpsend( (char *)&packet, cc, ipaddr, port, port, 1);
  352. # endif
  353. # ifdef DEBUG
  354.     fprintf(stderr, "wrote packet (%d)\n", cc);
  355.     fflush(stderr);
  356. # endif
  357. #else  SHM
  358.     aven_seg[0] = iavg1;
  359.     aven_seg[1] = iavg2;
  360.     aven_seg[2] = iavg3;
  361. #endif RWHOD
  362. } /* make_packet */
  363.  
  364. #ifdef RWHOD
  365. idletime(up)
  366. struct utmp *up;
  367. {
  368.     register int i;
  369.     register char *cp, *dp;
  370.     char ttyname[10];
  371.     struct stat buf;
  372.     time_t now;
  373.  
  374.     cp = "/dev/";
  375.     dp = ttyname;
  376.     
  377.     while( *cp != '\0' )        /* copy "/dev/" */
  378.         *dp++ = *cp++;
  379.  
  380.     cp = up->ut_line;            /* get line name */
  381.     if( *cp == 's' )            /* starts with an 's'? (sxtnnn) */
  382.         *dp++ = 'v';            /* insert a 'v' */
  383.  
  384.     for( i = 0; i < 8; i++ )        /* copy line name */
  385.         if( (*dp++ = *cp++) == '\0' ) break;    /* or until null */
  386.  
  387.     if( stat(ttyname, &buf) != 0 )    /* get file status */
  388.         return( 0 );
  389.  
  390.     time(&now);                /* get current time */
  391.     i = now - buf.st_atime;        /* get differnce from last acces */
  392.     return( i );            /* return idle time */
  393. } /* idletime */
  394. #endif RWHOD
  395. ------------------------------------------------------------------------------
  396.  
  397.  
  398. -- 
  399. ++Brandon (Resident Elf @ ncoast.UUCP)
  400.  ____   ______________
  401. /    \ / __   __   __ \   Brandon S. Allbery        <backbone>!ncoast!allbery
  402.  ___  | /__> /  \ /  \    aXcess Co., Consulting    ncoast!allbery@Case.CSNET
  403. /   \ | |    `--, `--,    6615 Center St. #A1-105        (...@relay.CS.NET)
  404. |     | \__/ \__/ \__/    Mentor, OH 44060-4101     
  405. \____/ \______________/   +1 216 974 9210
  406.  
  407.  
  408.