1 /* $OpenBSD: pigs.c,v 1.26 2013/06/02 06:23:17 guenther Exp $ */ 2 /* $NetBSD: pigs.c,v 1.3 1995/04/29 05:54:50 cgd Exp $ */ 3 4 /*- 5 * Copyright (c) 1980, 1992, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 /* 34 * Pigs display from Bill Reeves at Lucasfilm 35 */ 36 37 #include <sys/param.h> 38 #include <sys/dkstat.h> 39 #include <sys/resource.h> 40 #include <sys/time.h> 41 #include <sys/proc.h> 42 #include <sys/sysctl.h> 43 44 #include <curses.h> 45 #include <math.h> 46 #include <pwd.h> 47 #include <err.h> 48 #include <stdlib.h> 49 #include <string.h> 50 51 #include "systat.h" 52 53 int compar(const void *, const void *); 54 void print_pg(void); 55 int read_pg(void); 56 int select_pg(void); 57 void showpigs(int k); 58 59 static struct kinfo_proc *procbase = NULL; 60 static int nproc, pigs_cnt, *pb_indices = NULL; 61 static int onproc = -1; 62 63 static long stime[CPUSTATES]; 64 static double lccpu; 65 struct loadavg sysload; 66 67 68 69 field_def fields_pg[] = { 70 {"USER", 6, 16, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, 71 {"NAME", 10, 24, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, 72 {"PID", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 73 {"CPU", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 74 {"", 30, 60, 1, FLD_ALIGN_BAR, -1, 0, 0, 100}, 75 }; 76 77 #define FLD_PG_USER FIELD_ADDR(fields_pg,0) 78 #define FLD_PG_NAME FIELD_ADDR(fields_pg,1) 79 #define FLD_PG_PID FIELD_ADDR(fields_pg,2) 80 #define FLD_PG_VALUE FIELD_ADDR(fields_pg,3) 81 #define FLD_PG_BAR FIELD_ADDR(fields_pg,4) 82 83 /* Define views */ 84 field_def *view_pg_0[] = { 85 FLD_PG_PID, FLD_PG_USER, FLD_PG_NAME, FLD_PG_VALUE, FLD_PG_BAR, NULL 86 }; 87 88 89 /* Define view managers */ 90 struct view_manager pigs_mgr = { 91 "Pigs", select_pg, read_pg, NULL, print_header, 92 print_pg, keyboard_callback, NULL, NULL 93 }; 94 95 field_view views_pg[] = { 96 {view_pg_0, "pigs", '5', &pigs_mgr}, 97 {NULL, NULL, 0, NULL} 98 }; 99 100 101 #ifdef FSCALE 102 # define FIXED_LOADAVG FSCALE 103 # define FIXED_PCTCPU FSCALE 104 #endif 105 106 #ifdef FIXED_PCTCPU 107 typedef long pctcpu; 108 # define pctdouble(p) ((double)(p) / FIXED_PCTCPU) 109 #else 110 typedef double pctcpu; 111 # define pctdouble(p) (p) 112 #endif 113 114 int 115 select_pg(void) 116 { 117 num_disp = pigs_cnt; 118 return (0); 119 } 120 121 122 int 123 getprocs(void) 124 { 125 size_t size; 126 int mib[6] = {CTL_KERN, KERN_PROC, KERN_PROC_KTHREAD, 0, sizeof(struct kinfo_proc), 0}; 127 128 int st; 129 130 free(procbase); 131 procbase = NULL; 132 133 st = sysctl(mib, 6, NULL, &size, NULL, 0); 134 if (st == -1) 135 return (1); 136 137 size = 5 * size / 4; /* extra slop */ 138 if ((procbase = malloc(size + 1)) == NULL) 139 return (1); 140 141 mib[5] = (int)(size / sizeof(struct kinfo_proc)); 142 st = sysctl(mib, 6, procbase, &size, NULL, 0); 143 if (st == -1) 144 return (1); 145 146 nproc = (int)(size / sizeof(struct kinfo_proc)); 147 return (0); 148 } 149 150 151 int 152 read_pg(void) 153 { 154 static int cp_time_mib[] = { CTL_KERN, KERN_CPTIME }; 155 long ctimes[CPUSTATES]; 156 double t; 157 int i, k; 158 size_t size; 159 160 num_disp = pigs_cnt = 0; 161 162 if (getprocs()) { 163 error("Failed to read process info!"); 164 return 1; 165 } 166 167 if (nproc > onproc) { 168 int *p; 169 p = realloc(pb_indices, (nproc + 1) * sizeof(int)); 170 if (p == NULL) { 171 error("Out of Memory!"); 172 return 1; 173 } 174 pb_indices = p; 175 onproc = nproc; 176 } 177 178 memset(&procbase[nproc], 0, sizeof(*procbase)); 179 180 for (i = 0; i <= nproc; i++) 181 pb_indices[i] = i; 182 183 /* 184 * and for the imaginary "idle" process 185 */ 186 size = sizeof(ctimes); 187 sysctl(cp_time_mib, 2, &ctimes, &size, NULL, 0); 188 189 t = 0; 190 for (i = 0; i < CPUSTATES; i++) 191 t += ctimes[i] - stime[i]; 192 if (t == 0.0) 193 t = 1.0; 194 195 procbase[nproc].p_pctcpu = (ctimes[CP_IDLE] - stime[CP_IDLE]) / t / pctdouble(1); 196 for (i = 0; i < CPUSTATES; i++) 197 stime[i] = ctimes[i]; 198 199 qsort(pb_indices, nproc + 1, sizeof (int), compar); 200 201 pigs_cnt = 0; 202 for (k = 0; k < nproc + 1; k++) { 203 int j = pb_indices[k]; 204 if (pctdouble(procbase[j].p_pctcpu) < 0.01) 205 break; 206 pigs_cnt++; 207 } 208 209 num_disp = pigs_cnt; 210 return 0; 211 } 212 213 214 void 215 print_pg(void) 216 { 217 int n, count = 0; 218 219 for (n = dispstart; n < num_disp; n++) { 220 showpigs(pb_indices[n]); 221 count++; 222 if (maxprint > 0 && count >= maxprint) 223 break; 224 } 225 } 226 227 int 228 initpigs(void) 229 { 230 static int sysload_mib[] = {CTL_VM, VM_LOADAVG}; 231 static int cp_time_mib[] = { CTL_KERN, KERN_CPTIME }; 232 static int ccpu_mib[] = { CTL_KERN, KERN_CCPU }; 233 field_view *v; 234 size_t size; 235 fixpt_t ccpu; 236 237 size = sizeof(stime); 238 sysctl(cp_time_mib, 2, &stime, &size, NULL, 0); 239 240 size = sizeof(sysload); 241 sysctl(sysload_mib, 2, &sysload, &size, NULL, 0); 242 243 size = sizeof(ccpu); 244 sysctl(ccpu_mib, 2, &ccpu, &size, NULL, 0); 245 246 lccpu = log((double) ccpu / sysload.fscale); 247 248 for (v = views_pg; v->name != NULL; v++) 249 add_view(v); 250 251 return(1); 252 } 253 254 void 255 showpigs(int k) 256 { 257 struct kinfo_proc *kp; 258 double value; 259 char *uname, *pname; 260 261 if (procbase == NULL) 262 return; 263 264 value = pctdouble(procbase[k].p_pctcpu) * 100; 265 266 kp = &procbase[k]; 267 if (kp->p_comm[0] == '\0') { 268 uname = ""; 269 pname = "<idle>"; 270 } else { 271 uname = user_from_uid(kp->p_uid, 0); 272 pname = kp->p_comm; 273 print_fld_uint(FLD_PG_PID, kp->p_pid); 274 } 275 276 tb_start(); 277 tbprintf("%.2f", value); 278 print_fld_tb(FLD_PG_VALUE); 279 280 print_fld_str(FLD_PG_NAME, pname); 281 print_fld_str(FLD_PG_USER, uname); 282 print_fld_bar(FLD_PG_BAR, value); 283 284 end_line(); 285 } 286 287 288 int 289 compar(const void *a, const void *b) 290 { 291 int i1 = *((int *)a); 292 int i2 = *((int *)b); 293 294 return procbase[i1].p_pctcpu > 295 procbase[i2].p_pctcpu ? -1 : 1; 296 } 297 298