home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / NEXTSTEP / UNIX / Utilities / top-0.5-MI / machine / m_ncr3000.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-03  |  18.4 KB  |  706 lines

  1. /*
  2.  * top - a top users display for Unix
  3.  *
  4.  * SYNOPSIS:  For NCR 3000 series systems Release 2.00.02 and above -
  5.  *    works on 2.03.00 and earlier (and probably later) OS releases.
  6.  *     (Intel based System V Release 4)
  7.  *
  8.  * DESCRIPTION:
  9.  *      System V release 4     for NCR 3000 series OS Rel 02.03.00 and above
  10.  *
  11.  * LIBS:  -lelf
  12.  *
  13.  * AUTHORS:  Andrew Herbert     <andrew@werple.apana.org.au>
  14.  *           Robert Boucher     <boucher@sofkin.ca>
  15.  *           Jeff Janvrin    <jeff.janvrin@columbiasc.ncr.com>
  16.  *                              did the port to statfs (2.03)
  17.  */
  18.  
  19. #include "top.h"
  20. #include "machine.h"
  21. #include "utils.h"
  22. #include <stdio.h>
  23. #include <fcntl.h>
  24. #include <unistd.h>
  25. #include <stdlib.h>
  26. #include <errno.h>
  27. #include <dirent.h>
  28. #include <nlist.h>
  29. #include <string.h>
  30. #include <sys/types.h>
  31. #include <sys/stat.h>
  32. #include <sys/param.h>
  33. #include <sys/procfs.h>
  34. #include <sys/sysinfo.h>
  35. #include <sys/sysmacros.h>
  36. #include <sys/vmmeter.h>
  37. #include <vm/anon.h>
  38. #include <sys/priocntl.h>
  39. #include <sys/rtpriocntl.h>
  40. #include <sys/tspriocntl.h>
  41. #include <sys/procset.h>
  42. #include <sys/var.h>
  43.  
  44. #define UNIX "/stand/unix"
  45. #define KMEM "/dev/kmem"
  46. #define PROCFS "/proc"
  47. #define CPUSTATES    5
  48.  
  49. #ifndef PRIO_MAX
  50. #define PRIO_MAX    20
  51. #endif
  52. #ifndef PRIO_MIN
  53. #define PRIO_MIN    -20
  54. #endif
  55.  
  56. #ifndef FSCALE
  57. #define FSHIFT  8        /* bits to right of fixed binary point */
  58. #define FSCALE  (1<<FSHIFT)
  59. #endif
  60.  
  61. #define loaddouble(x) ((double)(x) / FSCALE)
  62. #define percent_cpu(x) ((double)(x)->pr_cpu / FSCALE)
  63. #define weighted_cpu(pct, pp) ( ((pp)->pr_time.tv_sec) == 0 ? 0.0 : \
  64.         ((pp)->pr_cpu) / ((pp)->pr_time.tv_sec) )
  65. #define pagetok(size) ctob(size) >> LOG1024
  66.  
  67. /* definitions for the index in the nlist array */
  68. #define X_AVENRUN    0
  69. #define X_MPID        1
  70. #define X_V        2
  71. #define X_NPROC        3
  72. #define X_ANONINFO    4
  73. #define X_TOTAL        5
  74. #define X_SYSINFO    6
  75.  
  76. static struct nlist nlst[] =
  77. {
  78. {"avenrun"},            /* 0 */
  79. {"mpid"},            /* 1 */
  80. {"v"},            /* 2 */
  81. {"nproc"},            /* 3 */
  82. {"anoninfo"},            /* 4 */
  83. {"total"},            /* 5 */
  84. {"sysinfo"},            /* 6 */
  85. {NULL}
  86. };
  87.  
  88. static unsigned long avenrun_offset;
  89. static unsigned long mpid_offset;
  90. static unsigned long nproc_offset;
  91. static unsigned long anoninfo_offset;
  92. static unsigned long total_offset;
  93. static unsigned long sysinfo_offset;
  94.  
  95. /* get_process_info passes back a handle.  This is what it looks like: */
  96.  
  97. struct handle
  98.   {
  99.     struct prpsinfo **next_proc;/* points to next valid proc pointer */
  100.     int remaining;        /* number of pointers remaining */
  101.   };
  102.  
  103. /*
  104.  *  These definitions control the format of the per-process area
  105.  */
  106.  
  107. static char header[] =
  108. "  PID X        PRI NICE  SIZE   RES STATE   TIME   WCPU    CPU COMMAND";
  109. /* 0123456   -- field to fill in starts at header+6 */
  110. #define UNAME_START 6
  111. #define Proc_format \
  112.     "%5d %-8.8s %3d %4d %5s %5s %-5s %6s %3d.0%% %5.2f%% %.16s"
  113.  
  114. char *state_abbrev[] =
  115. {"", "sleep", "run", "zombie", "stop", "start", "cpu", "swap"};
  116.  
  117. int process_states[8];
  118. char *procstatenames[] =
  119. {
  120.   "", " sleeping, ", " running, ", " zombie, ", " stopped, ",
  121.   " starting, ", " on cpu, ", " swapped, ",
  122.   NULL
  123. };
  124.  
  125. int cpu_states[CPUSTATES];
  126. char *cpustatenames[] =
  127. {"idle", "user", "kernel", "wait", "swap", NULL};
  128.  
  129. /* these are for detailing the memory statistics */
  130.  
  131. int memory_stats[5];
  132. char *memorynames[] =
  133. {"K real, ", "K active, ", "K free, ", "K swap, ", "K free swap", NULL};
  134.  
  135. static int kmem = -1;
  136. static int nproc;
  137. static int bytes;
  138. static int use_stats = 0;
  139. static struct prpsinfo *pbase;
  140. static struct prpsinfo **pref;
  141. static DIR *procdir;
  142.  
  143. /* useful externals */
  144. extern int errno;
  145. extern char *sys_errlist[];
  146. extern char *myname;
  147. extern int check_nlist ();
  148. extern int getkval ();
  149. extern void perror ();
  150. extern void getptable ();
  151. extern void quit ();
  152. extern int nlist ();
  153.  
  154. int
  155. machine_init (struct statics *statics)
  156.   {
  157.     static struct var v;
  158.  
  159.     /* fill in the statics information */
  160.     statics->procstate_names = procstatenames;
  161.     statics->cpustate_names = cpustatenames;
  162.     statics->memory_names = memorynames;
  163.  
  164.     /* get the list of symbols we want to access in the kernel */
  165.     if (nlist (UNIX, nlst))
  166.       {
  167.     (void) fprintf (stderr, "Unable to nlist %s\n", UNIX);
  168.     return (-1);
  169.       }
  170.  
  171.     /* make sure they were all found */
  172.     if (check_nlist (nlst) > 0)
  173.       return (-1);
  174.  
  175.     /* open kernel memory */
  176.     if ((kmem = open (KMEM, O_RDONLY)) == -1)
  177.       {
  178.     perror (KMEM);
  179.     return (-1);
  180.       }
  181.  
  182.     /* get the symbol values out of kmem */
  183.     /* NPROC Tuning parameter for max number of processes */
  184.     (void) getkval (nlst[X_V].n_value, (int *) &v, sizeof (struct var), nlst[X_V].n_name);
  185.     nproc = v.v_proc;
  186.  
  187.     /* stash away certain offsets for later use */
  188.     mpid_offset = nlst[X_MPID].n_value;
  189.     nproc_offset = nlst[X_NPROC].n_value;
  190.     avenrun_offset = nlst[X_AVENRUN].n_value;
  191.     anoninfo_offset = nlst[X_ANONINFO].n_value;
  192.     total_offset = nlst[X_TOTAL].n_value;
  193. /* JJ this may need to be changed */
  194.     sysinfo_offset = nlst[X_SYSINFO].n_value;
  195.  
  196.     /* allocate space for proc structure array and array of pointers */
  197.     bytes = nproc * sizeof (struct prpsinfo);
  198.     pbase = (struct prpsinfo *) malloc (bytes);
  199.     pref = (struct prpsinfo **) malloc (nproc * sizeof (struct prpsinfo *));
  200.  
  201.     /* Just in case ... */
  202.     if (pbase == (struct prpsinfo *) NULL || pref == (struct prpsinfo **) NULL)
  203.       {
  204.     (void) fprintf (stderr, "%s: can't allocate sufficient memory\n", myname);
  205.     return (-1);
  206.       }
  207.  
  208.     if (!(procdir = opendir (PROCFS)))
  209.       {
  210.     (void) fprintf (stderr, "Unable to open %s\n", PROCFS);
  211.     return (-1);
  212.       }
  213.  
  214.     if (chdir (PROCFS))
  215.       {                /* handy for later on when we're reading it */
  216.     (void) fprintf (stderr, "Unable to chdir to %s\n", PROCFS);
  217.     return (-1);
  218.       }
  219.  
  220.     /* all done! */
  221.     return (0);
  222.   }
  223.  
  224. char *
  225. format_header (char *uname_field)
  226. {
  227.   register char *ptr;
  228.  
  229.   ptr = header + UNAME_START;
  230.   while (*uname_field != '\0')
  231.     *ptr++ = *uname_field++;
  232.  
  233.   return (header);
  234. }
  235.  
  236. void
  237. get_system_info (struct system_info *si)
  238. {
  239.   long avenrun[3];
  240.   struct sysinfo sysinfo;
  241.   static struct sysinfo *mpinfo = NULL;    /* array, per-processor sysinfo structures. */
  242.   struct vmtotal total;
  243.   struct anoninfo anoninfo;
  244.   static time_t cp_old[CPUSTATES];
  245.   static time_t cp_diff[CPUSTATES];    /* for cpu state percentages */
  246.   static int num_cpus;
  247.   static int fd_cpu = 0;
  248.   register int i;
  249.  
  250.   if ( use_stats == 1) {
  251.     if ( fd_cpu == 0 ) {
  252.       if ((fd_cpu = open("/stats/cpuinfo", O_RDONLY)) == -1) {
  253.         (void) fprintf (stderr, "%s: Open of /stats/cpuinfo failed\n", myname);
  254.     quit(2);
  255.       }
  256.       if (read(fd_cpu, &num_cpus, sizeof(int)) != sizeof(int)) {
  257.         (void) fprintf (stderr, "%s: Read of /stats/cpuinfo failed\n", myname);
  258.     quit(2);
  259.       }
  260.       close(fd_cpu);
  261.     }
  262.     if (mpinfo == NULL) {
  263.       mpinfo = (struct sysinfo *)calloc(num_cpus, sizeof(mpinfo[0]));
  264.       if (mpinfo == NULL) {
  265.         (void) fprintf (stderr, "%s: can't allocate space for per-processor sysinfos\n", myname);
  266.         quit(12);
  267.       }
  268.     }
  269.     /* Read the per cpu sysinfo structures into mpinfo struct. */
  270.     read_sysinfos(num_cpus, mpinfo);
  271.     /* Add up all of the percpu sysinfos to get global sysinfo */
  272.     sysinfo_data(num_cpus, &sysinfo, mpinfo);
  273.   } else {
  274.     (void) getkval (sysinfo_offset, &sysinfo, sizeof (struct sysinfo), "sysinfo");
  275.   }
  276.  
  277.   /* convert cp_time counts to percentages */
  278.   (void) percentages (CPUSTATES, cpu_states, sysinfo.cpu, cp_old, cp_diff);
  279.  
  280.   /* get mpid -- process id of last process */
  281.   (void) getkval (mpid_offset, &(si->last_pid), sizeof (si->last_pid),
  282.           "mpid");
  283.  
  284.   /* get load average array */
  285.   (void) getkval (avenrun_offset, (int *) avenrun, sizeof (avenrun), "avenrun");
  286.  
  287.   /* convert load averages to doubles */
  288.   for (i = 0; i < 3; i++)
  289.     si->load_avg[i] = loaddouble (avenrun[i]);
  290.  
  291.   /* get total -- systemwide main memory usage structure */
  292.   (void) getkval (total_offset, (int *) (&total), sizeof (total), "total");
  293.   /* convert memory stats to Kbytes */
  294.   memory_stats[0] = pagetok (total.t_rm);
  295.   memory_stats[1] = pagetok (total.t_arm);
  296.   memory_stats[2] = pagetok (total.t_free);
  297.   (void) getkval (anoninfo_offset, (int *) (&anoninfo), sizeof (anoninfo),
  298.           "anoninfo");
  299.   memory_stats[3] = pagetok (anoninfo.ani_max - anoninfo.ani_free);
  300.   memory_stats[4] = pagetok (anoninfo.ani_max - anoninfo.ani_resv);
  301.  
  302.   /* set arrays and strings */
  303.   si->cpustates = cpu_states;
  304.   si->memory = memory_stats;
  305. }
  306.  
  307. static struct handle handle;
  308.  
  309. caddr_t
  310. get_process_info (
  311.            struct system_info *si,
  312.            struct process_select *sel,
  313.            int (*compare) ())
  314. {
  315.   register int i;
  316.   register int total_procs;
  317.   register int active_procs;
  318.   register struct prpsinfo **prefp;
  319.   register struct prpsinfo *pp;
  320.  
  321.   /* these are copied out of sel for speed */
  322.   int show_idle;
  323.   int show_system;
  324.   int show_uid;
  325.  
  326.   /* Get current number of processes */
  327.   (void) getkval (nproc_offset, (int *) (&nproc), sizeof (nproc), "nproc");
  328.  
  329.   /* read all the proc structures */
  330.   getptable (pbase);
  331.  
  332.   /* get a pointer to the states summary array */
  333.   si->procstates = process_states;
  334.  
  335.   /* set up flags which define what we are going to select */
  336.   show_idle = sel->idle;
  337.   show_system = sel->system;
  338.   show_uid = sel->uid != -1;
  339.  
  340.   /* count up process states and get pointers to interesting procs */
  341.   total_procs = 0;
  342.   active_procs = 0;
  343.   (void) memset (process_states, 0, sizeof (process_states));
  344.   prefp = pref;
  345.  
  346.   for (pp = pbase, i = 0; i < nproc; pp++, i++)
  347.     {
  348.       /*
  349.      *  Place pointers to each valid proc structure in pref[].
  350.      *  Process slots that are actually in use have a non-zero
  351.      *  status field.  Processes with SSYS set are system
  352.      *  processes---these get ignored unless show_sysprocs is set.
  353.      */
  354.       if (pp->pr_state != 0 &&
  355.       (show_system || ((pp->pr_flag & SSYS) == 0)))
  356.     {
  357.       total_procs++;
  358.       process_states[pp->pr_state]++;
  359.       if ((!pp->pr_zomb) &&
  360.           (show_idle || (pp->pr_state == SRUN) || (pp->pr_state == SONPROC)) &&
  361.           (!show_uid || pp->pr_uid == (uid_t) sel->uid))
  362.         {
  363.           *prefp++ = pp;
  364.           active_procs++;
  365.         }
  366.     }
  367.     }
  368.  
  369.   /* if requested, sort the "interesting" processes */
  370.   if (compare != NULL)
  371.       qsort ((char *) pref, active_procs, sizeof (struct prpsinfo *), compare);
  372.  
  373.   /* remember active and total counts */
  374.   si->p_total = total_procs;
  375.   si->p_active = active_procs;
  376.  
  377.   /* pass back a handle */
  378.   handle.next_proc = pref;
  379.   handle.remaining = active_procs;
  380.   return ((caddr_t) & handle);
  381. }
  382.  
  383. char fmt[MAX_COLS];            /* static area where result is built */
  384.  
  385. char *
  386. format_next_process (
  387.               caddr_t handle,
  388.               char *(*get_userid) ())
  389. {
  390.   register struct prpsinfo *pp;
  391.   struct handle *hp;
  392.   register long cputime;
  393.   register double pctcpu;
  394.  
  395.   /* find and remember the next proc structure */
  396.   hp = (struct handle *) handle;
  397.   pp = *(hp->next_proc++);
  398.   hp->remaining--;
  399.  
  400.   /* get the cpu usage and calculate the cpu percentages */
  401.   cputime = pp->pr_time.tv_sec;
  402.   pctcpu = percent_cpu (pp);
  403.  
  404.   /* format this entry */
  405.   (void) sprintf (fmt,
  406.           Proc_format,
  407.           pp->pr_pid,
  408.           (*get_userid) (pp->pr_uid),
  409.           pp->pr_pri - PZERO,
  410.           pp->pr_nice - NZERO,
  411.           format_k(pagetok (pp->pr_size)),
  412.           format_k(pagetok (pp->pr_rssize)),
  413.           state_abbrev[pp->pr_state],
  414.           format_time(cputime),
  415.           (pp->pr_cpu & 0377),
  416.           100.0 * pctcpu,
  417.           pp->pr_fname);
  418.  
  419.   /* return the result */
  420.   return (fmt);
  421. }
  422.  
  423. /*
  424.  * check_nlist(nlst) - checks the nlist to see if any symbols were not
  425.  *        found.  For every symbol that was not found, a one-line
  426.  *        message is printed to stderr.  The routine returns the
  427.  *        number of symbols NOT found.
  428.  */
  429. int
  430. check_nlist (register struct nlist *nlst)
  431. {
  432.   register int i;
  433.   struct stat stat_buf;
  434.  
  435.   /* check to see if we got ALL the symbols we requested */
  436.   /* this will write one line to stderr for every symbol not found */
  437.  
  438.   i = 0;
  439.   while (nlst->n_name != NULL)
  440.     {
  441.       if (nlst->n_type == 0)
  442.     {
  443.       if (strcmp("sysinfo", nlst->n_name) == 0)
  444.         {
  445.         /* check to see if /stats file system exists. If so,     */
  446.         /* ignore error.                     */
  447.         if ( !((stat("/stats/sysinfo", &stat_buf) == 0) && 
  448.           (stat_buf.st_mode & S_IFREG)) )
  449.           {
  450.             (void) fprintf (stderr, "kernel: no symbol named `%s'\n", nlst->n_name);
  451.             i = 1;
  452.           } else {
  453.             use_stats = 1;
  454.           }
  455.         } else {
  456.  
  457.           /* this one wasn't found */
  458.           (void) fprintf (stderr, "kernel: no symbol named `%s'\n", nlst->n_name);
  459.           i = 1;
  460.         }
  461.     }
  462.       nlst++;
  463.     }
  464.   return (i);
  465. }
  466.  
  467.  
  468. /*
  469.  *  getkval(offset, ptr, size, refstr) - get a value out of the kernel.
  470.  *    "offset" is the byte offset into the kernel for the desired value,
  471.  *      "ptr" points to a buffer into which the value is retrieved,
  472.  *      "size" is the size of the buffer (and the object to retrieve),
  473.  *      "refstr" is a reference string used when printing error meessages,
  474.  *        if "refstr" starts with a '!', then a failure on read will not
  475.  *          be fatal (this may seem like a silly way to do things, but I
  476.  *          really didn't want the overhead of another argument).
  477.  *
  478.  */
  479. int
  480. getkval (
  481.       unsigned long offset,
  482.       int *ptr,
  483.       int size,
  484.       char *refstr)
  485. {
  486.   if (lseek (kmem, (long) offset, 0) == -1)
  487.     {
  488.       if (*refstr == '!')
  489.     refstr++;
  490.       (void) fprintf (stderr, "%s: lseek to %s: %s\n",
  491.               myname, refstr, sys_errlist[errno]);
  492.       quit (22);
  493.     }
  494.   if (read (kmem, (char *) ptr, size) == -1)
  495.     if (*refstr == '!')
  496.       /* we lost the race with the kernel, process isn't in memory */
  497.       return (0);
  498.     else
  499.       {
  500.     (void) fprintf (stderr, "%s: reading %s: %s\n",
  501.             myname, refstr, sys_errlist[errno]);
  502.     quit (23);
  503.       }
  504.   return (1);
  505. }
  506.  
  507. /* comparison routine for qsort */
  508.  
  509. /*
  510.  *  proc_compare - comparison function for "qsort"
  511.  *    Compares the resource consumption of two processes using five
  512.  *      distinct keys.  The keys (in descending order of importance) are:
  513.  *      percent cpu, cpu ticks, state, resident set size, total virtual
  514.  *      memory usage.  The process states are ordered as follows (from least
  515.  *      to most important):  WAIT, zombie, sleep, stop, start, run.  The
  516.  *      array declaration below maps a process state index into a number
  517.  *      that reflects this ordering.
  518.  */
  519.  
  520.  
  521. unsigned char sorted_state[] =
  522. {
  523.   0,                /* not used        */
  524.   3,                /* sleep        */
  525.   6,                /* run            */
  526.   2,                /* zombie        */
  527.   4,                /* stop            */
  528.   5,                /* start        */
  529.   7,                /* run on a processor   */
  530.   1                /* being swapped (WAIT)    */
  531. };
  532.  
  533. int
  534. proc_compare (
  535.            struct prpsinfo **pp1,
  536.            struct prpsinfo **pp2)
  537. {
  538.     register struct prpsinfo *p1;
  539.     register struct prpsinfo *p2;
  540.     register long result;
  541.  
  542.     /* remove one level of indirection */
  543.     p1 = *pp1;
  544.     p2 = *pp2;
  545.  
  546.     /* compare percent cpu (pctcpu) */
  547.     if ((result = (long) (p2->pr_cpu - p1->pr_cpu)) == 0)
  548.       {
  549.     /* use cpticks to break the tie */
  550.     if ((result = p2->pr_time.tv_sec - p1->pr_time.tv_sec) == 0)
  551.       {
  552.         /* use process state to break the tie */
  553.         if ((result = (long) (sorted_state[p2->pr_state] -
  554.                   sorted_state[p1->pr_state])) == 0)
  555.           {
  556.         /* use priority to break the tie */
  557.         if ((result = p2->pr_oldpri - p1->pr_oldpri) == 0)
  558.           {
  559.             /* use resident set size (rssize) to break the tie */
  560.             if ((result = p2->pr_rssize - p1->pr_rssize) == 0)
  561.               {
  562.             /* use total memory to break the tie */
  563.             result = (p2->pr_size - p1->pr_size);
  564.               }
  565.           }
  566.           }
  567.       }
  568.       }
  569.     return (result);
  570.   }
  571.  
  572. /*
  573. get process table
  574. */
  575. void
  576. getptable (struct prpsinfo *baseptr)
  577. {
  578.   struct prpsinfo *currproc;    /* pointer to current proc structure    */
  579.   int numprocs = 0;
  580.   struct dirent *direntp;
  581.  
  582.   for (rewinddir (procdir); direntp = readdir (procdir);)
  583.     {
  584.       int fd;
  585.  
  586.       if ((fd = open (direntp->d_name, O_RDONLY)) < 0)
  587.     continue;
  588.  
  589.       currproc = &baseptr[numprocs];
  590.       if (ioctl (fd, PIOCPSINFO, currproc) < 0)
  591.     {
  592.       (void) close (fd);
  593.       continue;
  594.     }
  595.  
  596.       numprocs++;
  597.       (void) close (fd);
  598.     }
  599.  
  600.   if (nproc != numprocs)
  601.     nproc = numprocs;
  602. }
  603.  
  604. /* return the owner of the specified process, for use in commands.c as we're
  605.    running setuid root */
  606. uid_t
  607. proc_owner (pid_t pid)
  608. {
  609.   register struct prpsinfo *p;
  610.   int i;
  611.   for (i = 0, p = pbase; i < nproc; i++, p++)
  612.     if (p->pr_pid == pid)
  613.       return (p->pr_uid);
  614.  
  615.   return (-1);
  616. }
  617.  
  618. int
  619. setpriority (int dummy, int who, int niceval)
  620. {
  621.   int scale;
  622.   int prio;
  623.   pcinfo_t pcinfo;
  624.   pcparms_t pcparms;
  625.   tsparms_t *tsparms;
  626.  
  627.   strcpy (pcinfo.pc_clname, "TS");
  628.   if (priocntl (0, 0, PC_GETCID, (caddr_t) & pcinfo) == -1)
  629.     return (-1);
  630.  
  631.   prio = niceval;
  632.   if (prio > PRIO_MAX)
  633.     prio = PRIO_MAX;
  634.   else if (prio < PRIO_MIN)
  635.     prio = PRIO_MIN;
  636.  
  637.   tsparms = (tsparms_t *) pcparms.pc_clparms;
  638.   scale = ((tsinfo_t *) pcinfo.pc_clinfo)->ts_maxupri;
  639.   tsparms->ts_uprilim = tsparms->ts_upri = -(scale * prio) / 20;
  640.   pcparms.pc_cid = pcinfo.pc_cid;
  641.  
  642.   if (priocntl (P_PID, who, PC_SETPARMS, (caddr_t) & pcparms) == -1)
  643.     return (-1);
  644.  
  645.   return (0);
  646. }
  647.  
  648. /****************************************************************
  649.  * read_sysinfos() -                        *
  650.  *    Read all of the CPU specific sysinfo sturctures in from    *
  651.  *    the /stats file system.                    *
  652.  ****************************************************************/
  653. read_sysinfos(num_cpus, buf)
  654.     int num_cpus;
  655.     struct sysinfo    *buf;
  656. {
  657.  
  658.     static int    fd1=0;    /* file descriptor for /stats/sysinfo */
  659.     int        read_sz;
  660.  
  661.     /* Open /stats/sysinfo one time only and leave it open */
  662.     if (fd1==0) { 
  663.         if ((fd1 = open("/stats/sysinfo", O_RDONLY)) == -1)
  664.             (void) fprintf (stderr, "%s: Open of /stats/sysinfo failed\n", myname);
  665.     }
  666.     /* reset the read pointer to the beginning of the file */
  667.     if (lseek(fd1, 0L, SEEK_SET) == -1)
  668.         (void) fprintf (stderr, "%s: lseek to beginning of /stats/sysinfo failed\n", myname);
  669.     read_sz = num_cpus * sizeof(buf[0]);
  670.     if (read(fd1, buf, read_sz) != read_sz)
  671.         (void) fprintf (stderr, "%s: Read of /stats/sysinfo failed\n", myname);
  672. }
  673.  
  674. /****************************************************************
  675.  * sysinfo_data() -                        *
  676.  *    Add up all of the CPU specific sysinfo sturctures to    *
  677.  *    make the GLOBAL sysinfo.                *
  678.  ****************************************************************/
  679. sysinfo_data(num_cpus, global_si, percpu_si)
  680.     int num_cpus;
  681.     struct sysinfo    *global_si;
  682.     struct sysinfo    *percpu_si;
  683. {
  684.     struct sysinfo    *percpu_p;
  685.     int        cpu, i, *global, *src;
  686.  
  687.     /* null out the global statistics from last sample */
  688.     memset(global_si, 0, sizeof(struct sysinfo));
  689.  
  690.     percpu_p = (struct sysinfo *)percpu_si;
  691.     for(cpu = 0; cpu < num_cpus; cpu++) {
  692.         global = (int *)global_si;
  693.         src = (int *)percpu_p;
  694.  
  695.         /* assume sysinfo ends on an int boundary */
  696.         /* Currently, all of the struct sysinfo members are the same
  697.          * size as an int. If that changes, we may not be able to
  698.          * do this. But this should be safe.
  699.          */
  700.         for(i=0; i<sizeof(struct sysinfo)/sizeof(int); i++) {
  701.             *global++ += *src++;
  702.         }
  703.         percpu_p++;
  704.     }
  705. }
  706.