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