1 /* $NetBSD: pigs.c,v 1.19 2000/06/04 18:29:13 mycroft Exp $ */ 2 3 /*- 4 * Copyright (c) 1980, 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <sys/cdefs.h> 37 #ifndef lint 38 #if 0 39 static char sccsid[] = "@(#)pigs.c 8.2 (Berkeley) 9/23/93"; 40 #endif 41 __RCSID("$NetBSD: pigs.c,v 1.19 2000/06/04 18:29:13 mycroft Exp $"); 42 #endif /* not lint */ 43 44 /* 45 * Pigs display from Bill Reeves at Lucasfilm 46 */ 47 48 #include <sys/param.h> 49 #include <sys/dkstat.h> 50 #include <sys/dir.h> 51 #include <sys/time.h> 52 #include <sys/proc.h> 53 #include <sys/sched.h> 54 #include <sys/sysctl.h> 55 56 #include <curses.h> 57 #include <math.h> 58 #include <nlist.h> 59 #include <pwd.h> 60 #include <stdlib.h> 61 #include <string.h> 62 63 #include "extern.h" 64 #include "systat.h" 65 #include "ps.h" 66 67 int compare_pctcpu __P((const void *, const void *)); 68 69 int nproc; 70 struct p_times *pt; 71 72 u_int64_t stime[CPUSTATES]; 73 long mempages; 74 int fscale; 75 double lccpu; 76 77 #ifndef P_ZOMBIE 78 #define P_ZOMBIE(p) ((p)->p_stat == SZOMB) 79 #endif 80 81 WINDOW * 82 openpigs() 83 { 84 85 return (subwin(stdscr, LINES-5-1, 0, 5, 0)); 86 } 87 88 void 89 closepigs(w) 90 WINDOW *w; 91 { 92 93 if (w == NULL) 94 return; 95 wclear(w); 96 wrefresh(w); 97 delwin(w); 98 } 99 100 101 void 102 showpigs() 103 { 104 int i, y, k; 105 struct eproc *ep; 106 float total; 107 int factor; 108 const char *pname; 109 char pidname[30], pidstr[7], usrstr[9]; 110 111 if (pt == NULL) 112 return; 113 /* Accumulate the percent of cpu per user. */ 114 total = 0.0; 115 for (i = 0; i <= nproc; i++) { 116 /* Accumulate the percentage. */ 117 total += pt[i].pt_pctcpu; 118 } 119 120 if (total < 1.0) 121 total = 1.0; 122 factor = 50.0/total; 123 124 qsort(pt, nproc + 1, sizeof (struct p_times), compare_pctcpu); 125 y = 1; 126 i = nproc + 1; 127 if (i > getmaxy(wnd)-1) 128 i = getmaxy(wnd)-1; 129 for (k = 0; i > 0 && pt[k].pt_pctcpu > 0.01; i--, y++, k++) { 130 if (pt[k].pt_kp == NULL) { 131 pname = "<idle>"; 132 pidstr[0] = '\0'; 133 usrstr[0] = '\0'; 134 } 135 else { 136 ep = &pt[k].pt_kp->kp_eproc; 137 pname = pt[k].pt_kp->kp_proc.p_comm; 138 snprintf(pidstr, sizeof(pidstr), "%5d", pt[k].pt_kp->kp_proc.p_pid); 139 snprintf(usrstr, sizeof(usrstr), "%8s", user_from_uid(ep->e_ucred.cr_uid, 0)); 140 } 141 wmove(wnd, y, 0); 142 wclrtoeol(wnd); 143 mvwaddstr(wnd, y, 0, usrstr); 144 mvwaddstr(wnd, y, 9, pidstr); 145 (void)snprintf(pidname, sizeof(pidname), "%9.9s", pname); 146 mvwaddstr(wnd, y, 15, pidname); 147 mvwhline(wnd, y, 25, 'X', pt[k].pt_pctcpu*factor + 0.5); 148 } 149 wmove(wnd, y, 0); wclrtobot(wnd); 150 } 151 152 static struct nlist namelist[] = { 153 #define X_FIRST 0 154 #define X_CCPU 0 155 { "_ccpu" }, 156 #define X_FSCALE 1 157 { "_fscale" }, 158 #define X_PHYSMEM 2 159 { "_physmem" }, 160 { "" } 161 }; 162 163 int 164 initpigs() 165 { 166 fixpt_t ccpu; 167 168 if (namelist[X_FIRST].n_type == 0) { 169 if (kvm_nlist(kd, namelist)) { 170 nlisterr(namelist); 171 return(0); 172 } 173 if (namelist[X_FIRST].n_type == 0) { 174 error("namelist failed"); 175 return(0); 176 } 177 } 178 (void) fetch_cptime(stime); 179 KREAD(NPTR(X_PHYSMEM), &mempages, sizeof (mempages)); 180 NREAD(X_CCPU, &ccpu, sizeof ccpu); 181 NREAD(X_FSCALE, &fscale, sizeof fscale); 182 lccpu = log((double) ccpu / fscale); 183 184 return(1); 185 } 186 187 void 188 fetchpigs() 189 { 190 int i; 191 float time; 192 struct proc *pp; 193 float *pctp; 194 struct kinfo_proc *kpp; 195 u_int64_t ctime[CPUSTATES]; 196 double t; 197 static int lastnproc = 0; 198 199 if (namelist[X_FIRST].n_type == 0) 200 return; 201 if ((kpp = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nproc)) == NULL) { 202 error("%s", kvm_geterr(kd)); 203 if (pt) 204 free(pt); 205 return; 206 } 207 if (nproc > lastnproc) { 208 free(pt); 209 if ((pt = 210 malloc((nproc + 1) * sizeof(struct p_times))) == NULL) { 211 error("Out of memory"); 212 die(0); 213 } 214 } 215 lastnproc = nproc; 216 /* 217 * calculate %cpu for each proc 218 */ 219 for (i = 0; i < nproc; i++) { 220 pt[i].pt_kp = &kpp[i]; 221 pp = &kpp[i].kp_proc; 222 pctp = &pt[i].pt_pctcpu; 223 time = pp->p_swtime; 224 if (P_ZOMBIE(pp) || 225 time == 0 || (pp->p_flag & P_INMEM) == 0) 226 *pctp = 0; 227 else 228 *pctp = ((double) pp->p_pctcpu / 229 fscale) / (1.0 - exp(time * lccpu)); 230 } 231 /* 232 * and for the imaginary "idle" process 233 */ 234 (void) fetch_cptime(ctime); 235 t = 0; 236 for (i = 0; i < CPUSTATES; i++) 237 t += ctime[i] - stime[i]; 238 if (t == 0.0) 239 t = 1.0; 240 pt[nproc].pt_kp = NULL; 241 pt[nproc].pt_pctcpu = (ctime[CP_IDLE] - stime[CP_IDLE]) / t; 242 for (i = 0; i < CPUSTATES; i++) 243 stime[i] = ctime[i]; 244 } 245 246 void 247 labelpigs() 248 { 249 wmove(wnd, 0, 0); 250 wclrtoeol(wnd); 251 mvwaddstr(wnd, 0, 25, "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); 252 } 253 254 int 255 compare_pctcpu(a, b) 256 const void *a, *b; 257 { 258 return (((struct p_times *) a)->pt_pctcpu > 259 ((struct p_times *) b)->pt_pctcpu)? -1: 1; 260 } 261