BSD 4_4_Lite1 release
[unix-history] / usr / src / usr.bin / systat / pigs.c
index f219ffa..4c49494 100644 (file)
-#ifndef lint
-static char sccsid[] = "@(#)pigs.c     1.1 (Lucasfilm) %G%";
-#endif
+/*-
+ * Copyright (c) 1980, 1992, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
 
 
+#ifndef lint
+static char sccsid[] = "@(#)pigs.c     8.2 (Berkeley) 9/23/93";
+#endif /* not lint */
+
+/*
+ * Pigs display from Bill Reeves at Lucasfilm
+ */
+
+#include <sys/param.h>
+#include <sys/dkstat.h>
+#include <sys/dir.h>
+#include <sys/time.h>
+#include <sys/proc.h>
+#include <sys/sysctl.h>
+
+#include <curses.h>
+#include <math.h>
+#include <nlist.h>
+#include <pwd.h>
+#include <stdlib.h>
+
+#include "extern.h"
 #include "systat.h"
 
 #include "systat.h"
 
-showpigs()
+int compar __P((const void *, const void *));
+
+static int nproc;
+static struct p_times {
+       float pt_pctcpu;
+       struct kinfo_proc *pt_kp;
+} *pt;
+
+static long stime[CPUSTATES];
+static int     fscale;
+static double  lccpu;
+
+WINDOW *
+openpigs()
 {
 {
-        register short auid;
-        register int i, j, y;
-        register float max;
-        register struct p_times *ptptr;
-        struct p_times temppt;
-        register struct users *knptr;
-        char *getpname(), *pnamp;
-
-        /* Accumulate the percent of cpu per user. */
-        ptptr = pt;
-        numprocs = 0;
-        total = 0.0;
-        for (i = 0; i < nproc; i++) {
-                /* discard inactive processes */
-                if (ptptr->pt_uid == -1) {
-                        ptptr++;
-                        continue;
-                }
-                /* Accumulate the percentage. */
-                total += ptptr->pt_pctcpu;
-                numprocs++;
-                ptptr++;
-        }
-
-        pt[numprocs].pt_pctcpu = 1.0 - total;
-        pt[numprocs].pt_uid = -1;
-        pt[numprocs].pt_pid = -1;
-        pt[numprocs].pt_pp = NULL;
-
-        if (total < 1.0)
-                total = 1.0;
-        factor = 50.0/total;
-
-        /* Find the top ten by executing a "bubble pass" ten times. */
-        y = numprocs + 1 < 15 ? numprocs + 1 : 15;
-        for (i = 0; i < y; i++) {
-                ptptr = &pt[i];
-                max = -10000.0;
-                maxind = i;
-                for (j = i; j < numprocs + 1; j++) {
-                        if (ptptr->pt_pctcpu > max) {
-                                max = ptptr->pt_pctcpu;
-                                maxind = j;
-                        }
-                        ptptr++;
-                }
-                if (maxind != i) {
-                        temppt = pt[i];
-                        pt[i] = pt[maxind];
-                        pt[maxind] = temppt;
-                }
-        }
-
-        /* Display the top fifteen. */
-        y = 4;
-        ptptr = pt;
-        i = numprocs+1 < 15 ? numprocs+1 : 15;
-        for (; i > 0 && ptptr->pt_pctcpu > 0.01; i--) {
-                /* Find the user's name. */
-                knptr = known;
-                auid = ptptr->pt_uid;
-                for (j = numknown - 1; j >= 0; j--) {
-                        if (knptr->k_uid == auid) {
-                                namp = knptr->k_name;
-                                break;
-                        }
-                        knptr++;
-                }
-                if (j < 0) {
-                        if (numknown < 30) {
-                                knptr = &known[numknown];
-                                namp = strncpy(knptr->k_name,
-                                    getpwuid(auid)->pw_name, 15);
-                                knptr->k_name[15] = '\0';
-                                knptr->k_uid = auid;
-                                numknown++;
-                        } else
-                                namp = getpwuid(auid)-> pw_name;
-                }
-                pnamp = getpname(ptptr->pt_pid, ptptr->pt_pp);
-                wmove(wnd, y, 0);
-                wclrtoeol(wnd);
-                mvwaddstr(wnd, y, 0, namp);
-                sprintf(pidname, "%8.8s", pnamp);
-                mvwaddstr(wnd, y, 6, pidname);
-                wmove(wnd, y++, 15);
-                for (j = ptptr->pt_pctcpu*factor + 0.5; j > 0; j--)
-                        waddch(wnd, 'X');
-                ptptr++;
-        }
-
-        while (y < 19) {
-                wmove(wnd, y++, 0);
-                wclrtoeol(wnd);
-        }
+       return (subwin(stdscr, LINES-5-1, 0, 5, 0));
 }
 
 }
 
-openpigs()
+void
+closepigs(w)
+       WINDOW *w;
 {
 {
+       if (w == NULL)
+               return;
+       wclear(w);
+       wrefresh(w);
+       delwin(w);
+}
 
 
-        kmemf = "/dev/kmem";
-        kmem = open(kmemf, 0);
-        if (kmem < 0) {
-                perror(kmemf);
-                exit(1);
-        }
-        memf = "/dev/mem";
-        mem = open(memf, 0);
-        if (mem < 0) {
-                perror(memf);
-                exit(1);
-        }
-        swapf = "/dev/drum";
-        swap = open(swapf, 0);
-        if (swap < 0) {
-                perror(swapf);
-                exit(1);
-        }
+
+void
+showpigs()
+{
+       register int i, j, y, k;
+       struct  eproc *ep;
+       float total;
+       int factor;
+       char *uname, *pname, pidname[30];
+
+       if (pt == NULL)
+               return;
+       /* Accumulate the percent of cpu per user. */
+       total = 0.0;
+       for (i = 0; i <= nproc; i++) {
+               /* Accumulate the percentage. */
+               total += pt[i].pt_pctcpu;
+       }
+
+       if (total < 1.0)
+               total = 1.0;
+       factor = 50.0/total;
+
+        qsort(pt, nproc + 1, sizeof (struct p_times), compar);
+       y = 1;
+       i = nproc + 1;
+       if (i > wnd->maxy-1)
+               i = wnd->maxy-1;
+       for (k = 0; i > 0 && pt[k].pt_pctcpu > 0.01; i--, y++, k++) {
+               if (pt[k].pt_kp == NULL) {
+                       uname = "";
+                       pname = "<idle>";
+               }
+               else {
+                       ep = &pt[k].pt_kp->kp_eproc;
+                       uname = (char *)user_from_uid(ep->e_ucred.cr_uid, 0);
+                       pname = pt[k].pt_kp->kp_proc.p_comm;
+               }
+               wmove(wnd, y, 0);
+               wclrtoeol(wnd);
+               mvwaddstr(wnd, y, 0, uname);
+               sprintf(pidname, "%10.10s", pname, 0);
+               mvwaddstr(wnd, y, 9, pidname);
+               wmove(wnd, y, 20);
+               for (j = pt[k].pt_pctcpu*factor + 0.5; j > 0; j--)
+                       waddch(wnd, 'X');
+       }
+       wmove(wnd, y, 0); wclrtobot(wnd);
 }
 
 }
 
-/* these don't belong here */
-#define X_PROC          0
-#define X_NPROC         1
-#define X_USRPTMAP      4
-#define X_USRPT         5
+static struct nlist namelist[] = {
+#define X_FIRST                0
+#define X_CPTIME       0
+       { "_cp_time" },
+#define X_CCPU          1
+       { "_ccpu" },
+#define X_FSCALE        2
+       { "_fscale" },
+
+       { "" }
+};
 
 
-struct proc *kprocp;
+int
+initpigs()
+{
+       fixpt_t ccpu;
+
+       if (namelist[X_FIRST].n_type == 0) {
+               if (kvm_nlist(kd, namelist)) {
+                       nlisterr(namelist);
+                       return(0);
+               }
+               if (namelist[X_FIRST].n_type == 0) {
+                       error("namelist failed");
+                       return(0);
+               }
+       }
+       KREAD(NPTR(X_CPTIME), stime, sizeof (stime));
+       NREAD(X_CCPU, &ccpu, LONG);
+       NREAD(X_FSCALE,  &fscale, LONG);
+       lccpu = log((double) ccpu / fscale);
+
+       return(1);
+}
 
 
+void
 fetchpigs()
 {
 fetchpigs()
 {
-        register int i;
-        register struct p_times *prt;
-        register float time;
-        register struct proc *pp;
-
-        if (procp == NULL) {
-                procp = getw(nlst[X_PROC].n_value);
-                nproc = getw(nlst[X_NPROC].n_value);
-                kprocp = (struct proc *)malloc(sizeof (*kprocp) * nproc);
-        }
-        if (usrpt == NULL) {
-                usrpt = (struct pte *)nlst[X_USRPT].n_value;
-                Usrptma = (struct pte *)nlst[X_USRPTMAP].n_value;
-                pt = (struct p_times *)malloc(nproc * sizeof (struct p_times));
-                return;
-        }
-        prt = pt;
-        lseek(kmem, procp, L_SET);
-        read(kmem, kprocp, sizeof (struct proc) * nproc);
-        for (i = 0, pp = kprocp; i < nproc; i++, pp++) {
-                time = pp->p_time;
-                if (time == 0 || (pp->p_flag & SLOAD) == 0)
-                        continue;
-                prt->pt_pid = pp->p_pid;
-                prt->pt_pp = pp;
-                prt->pt_pctcpu = pp->p_pctcpu / (1.0 - exp(time * lccpu));
-                prt->pt_uid = pp->p_uid;
-                prt++;
-        }
-        for (; prt < &pt[nproc]; prt++)
-                prt->pt_uid = -1;
+       register int i;
+       register float time;
+       register struct proc *pp;
+       register float *pctp;
+       struct kinfo_proc *kpp;
+       long ctime[CPUSTATES];
+       double t;
+       static int lastnproc = 0;
+
+       if (namelist[X_FIRST].n_type == 0)
+               return;
+       if ((kpp = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nproc)) == NULL) {
+               error("%s", kvm_geterr(kd));
+               if (pt)
+                       free(pt);
+               return;
+       }
+       if (nproc > lastnproc) {
+               free(pt);
+               if ((pt =
+                   malloc((nproc + 1) * sizeof(struct p_times))) == NULL) {
+                       error("Out of memory");
+                       die(0);
+               }
+       }
+       lastnproc = nproc;
+       /*
+        * calculate %cpu for each proc
+        */
+       for (i = 0; i < nproc; i++) {
+               pt[i].pt_kp = &kpp[i];
+               pp = &kpp[i].kp_proc;
+               pctp = &pt[i].pt_pctcpu;
+               time = pp->p_swtime;
+               if (time == 0 || (pp->p_flag & P_INMEM) == 0)
+                       *pctp = 0;
+               else
+                       *pctp = ((double) pp->p_pctcpu / 
+                                       fscale) / (1.0 - exp(time * lccpu));
+       }
+       /*
+        * and for the imaginary "idle" process
+        */
+       KREAD(NPTR(X_CPTIME), ctime, sizeof (ctime));
+       t = 0;
+       for (i = 0; i < CPUSTATES; i++)
+               t += ctime[i] - stime[i];
+       if (t == 0.0)
+               t = 1.0;
+       pt[nproc].pt_kp = NULL;
+       pt[nproc].pt_pctcpu = (ctime[CP_IDLE] - stime[CP_IDLE]) / t;
+       for (i = 0; i < CPUSTATES; i++)
+               stime[i] = ctime[i];
 }
 
 }
 
+void
 labelpigs()
 {
 labelpigs()
 {
+       wmove(wnd, 0, 0);
+       wclrtoeol(wnd);
+       mvwaddstr(wnd, 0, 20,
+           "/0   /10  /20  /30  /40  /50  /60  /70  /80  /90  /100");
+}
 
 
-        move(5, 0);
-        clrtoeol();
-        mvaddstr(5, 20,
-                "/0   /10  /20  /30  /40  /50  /60  /70  /80  /90  /100");
+int
+compar(a, b)
+       const void *a, *b;
+{
+       return (((struct p_times *) a)->pt_pctcpu >
+               ((struct p_times *) b)->pt_pctcpu)? -1: 1;
 }
 }