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