1177633Sdfr/* $OpenBSD: pigs.c,v 1.33 2022/02/22 17:35:01 deraadt Exp $ */ 2177633Sdfr/* $NetBSD: pigs.c,v 1.3 1995/04/29 05:54:50 cgd Exp $ */ 3261046Smav 4261046Smav/*- 5261046Smav * Copyright (c) 1980, 1992, 1993 6261046Smav * The Regents of the University of California. All rights reserved. 7261046Smav * 8261046Smav * Redistribution and use in source and binary forms, with or without 9261046Smav * modification, are permitted provided that the following conditions 10261046Smav * are met: 11261046Smav * 1. Redistributions of source code must retain the above copyright 12261046Smav * notice, this list of conditions and the following disclaimer. 13261046Smav * 2. Redistributions in binary form must reproduce the above copyright 14261046Smav * notice, this list of conditions and the following disclaimer in the 15261046Smav * documentation and/or other materials provided with the distribution. 16261046Smav * 3. Neither the name of the University nor the names of its contributors 17177633Sdfr * may be used to endorse or promote products derived from this software 18261046Smav * without specific prior written permission. 19261046Smav * 20261046Smav * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21261046Smav * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22261046Smav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23261046Smav * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24261046Smav * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25261046Smav * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26261046Smav * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27261046Smav * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28261046Smav * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29177633Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30177633Sdfr * SUCH DAMAGE. 31177633Sdfr */ 32177633Sdfr 33177633Sdfr/* 34177633Sdfr * Pigs display from Bill Reeves at Lucasfilm 35177633Sdfr */ 36177633Sdfr 37177633Sdfr#include <sys/types.h> 38177633Sdfr#include <sys/signal.h> 39177633Sdfr#include <sys/proc.h> 40177633Sdfr#include <sys/resource.h> 41177633Sdfr#include <sys/sched.h> 42177633Sdfr#include <sys/sysctl.h> 43177633Sdfr#include <sys/time.h> 44177633Sdfr 45177633Sdfr#include <curses.h> 46177633Sdfr#include <math.h> 47177633Sdfr#include <pwd.h> 48177633Sdfr#include <err.h> 49177633Sdfr#include <stdlib.h> 50193650Srwatson#include <string.h> 51177633Sdfr 52177633Sdfr#include "systat.h" 53177633Sdfr 54177633Sdfrint compar(const void *, const void *); 55184588Sdfrvoid print_pg(void); 56184588Sdfrint read_pg(void); 57184588Sdfrint select_pg(void); 58184588Sdfrvoid showpigs(int k); 59184588Sdfr 60184588Sdfrstatic struct kinfo_proc *procbase = NULL; 61184588Sdfrstatic int nproc, pigs_cnt, *pb_indices = NULL; 62177633Sdfrstatic int onproc = -1; 63177633Sdfr 64177633Sdfrstatic long stime[CPUSTATES]; 65177633Sdfrstatic double lccpu; 66177633Sdfrstruct loadavg sysload; 67177633Sdfr 68177633Sdfr 69177633Sdfr 70177633Sdfrfield_def fields_pg[] = { 71177633Sdfr {"USER", 6, 16, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, 72177633Sdfr {"NAME", 10, 24, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, 73177633Sdfr {"PID", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 74177633Sdfr {"CPU", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 75177633Sdfr {"", 30, 60, 1, FLD_ALIGN_BAR, -1, 0, 0, 100}, 76177633Sdfr}; 77177633Sdfr 78177633Sdfr#define FLD_PG_USER FIELD_ADDR(fields_pg,0) 79177633Sdfr#define FLD_PG_NAME FIELD_ADDR(fields_pg,1) 80177633Sdfr#define FLD_PG_PID FIELD_ADDR(fields_pg,2) 81177633Sdfr#define FLD_PG_VALUE FIELD_ADDR(fields_pg,3) 82177633Sdfr#define FLD_PG_BAR FIELD_ADDR(fields_pg,4) 83177633Sdfr 84177633Sdfr/* Define views */ 85177633Sdfrfield_def *view_pg_0[] = { 86177633Sdfr FLD_PG_PID, FLD_PG_USER, FLD_PG_NAME, FLD_PG_VALUE, FLD_PG_BAR, NULL 87184588Sdfr}; 88184588Sdfr 89177633Sdfr 90177633Sdfr/* Define view managers */ 91177633Sdfrstruct view_manager pigs_mgr = { 92177633Sdfr "Pigs", select_pg, read_pg, NULL, print_header, 93177633Sdfr print_pg, keyboard_callback, NULL, NULL 94177633Sdfr}; 95177633Sdfr 96177633Sdfrfield_view views_pg[] = { 97177633Sdfr {view_pg_0, "pigs", '5', &pigs_mgr}, 98177633Sdfr {NULL, NULL, 0, NULL} 99177633Sdfr}; 100184588Sdfr 101184588Sdfrint fscale; 102184588Sdfr 103184588Sdfr#define pctdouble(p) ((double)(p) / fscale) 104184588Sdfr 105177633Sdfrtypedef long pctcpu; 106177633Sdfr 107177633Sdfrint 108177633Sdfrselect_pg(void) 109177633Sdfr{ 110177633Sdfr int mib[] = { CTL_KERN, KERN_FSCALE }; 111177633Sdfr size_t size = sizeof(fscale); 112184588Sdfr 113184588Sdfr if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), 114184588Sdfr &fscale, &size, NULL, 0) == -1) 115184588Sdfr return (-1); 116184588Sdfr num_disp = pigs_cnt; 117184588Sdfr return (0); 118184588Sdfr} 119184588Sdfr 120184588Sdfr 121184588Sdfrint 122184588Sdfrgetprocs(void) 123184588Sdfr{ 124184588Sdfr size_t size; 125184588Sdfr int mib[6] = {CTL_KERN, KERN_PROC, KERN_PROC_KTHREAD, 0, sizeof(struct kinfo_proc), 0}; 126184588Sdfr 127184588Sdfr int st; 128184588Sdfr 129184588Sdfr free(procbase); 130184588Sdfr procbase = NULL; 131184588Sdfr 132184588Sdfr st = sysctl(mib, 6, NULL, &size, NULL, 0); 133184588Sdfr if (st == -1) 134184588Sdfr return (1); 135184588Sdfr 136184588Sdfr size = 5 * size / 4; /* extra slop */ 137184588Sdfr if ((procbase = malloc(size + 1)) == NULL) 138184588Sdfr return (1); 139184588Sdfr 140184588Sdfr mib[5] = (int)(size / sizeof(struct kinfo_proc)); 141184588Sdfr st = sysctl(mib, 6, procbase, &size, NULL, 0); 142177633Sdfr if (st == -1) 143177633Sdfr return (1); 144177633Sdfr 145177633Sdfr nproc = (int)(size / sizeof(struct kinfo_proc)); 146184588Sdfr return (0); 147184588Sdfr} 148177633Sdfr 149177633Sdfr 150177633Sdfrint 151177633Sdfrread_pg(void) 152184588Sdfr{ 153184588Sdfr static int cp_time_mib[] = { CTL_KERN, KERN_CPTIME }; 154184588Sdfr long ctimes[CPUSTATES]; 155177633Sdfr double t; 156184588Sdfr int i, k; 157184588Sdfr size_t size; 158184588Sdfr 159184588Sdfr num_disp = pigs_cnt = 0; 160184588Sdfr 161184588Sdfr if (getprocs()) { 162184588Sdfr error("Failed to read process info!"); 163184588Sdfr return 1; 164184588Sdfr } 165184588Sdfr 166184588Sdfr if (nproc > onproc) { 167184588Sdfr int *p; 168194498Sbrooks p = reallocarray(pb_indices, nproc + 1, sizeof(int)); 169177633Sdfr if (p == NULL) { 170177633Sdfr error("Out of Memory!"); 171177633Sdfr return 1; 172177633Sdfr } 173177633Sdfr pb_indices = p; 174177633Sdfr onproc = nproc; 175177633Sdfr } 176177633Sdfr 177177633Sdfr memset(&procbase[nproc], 0, sizeof(*procbase)); 178184588Sdfr 179177633Sdfr for (i = 0; i <= nproc; i++) 180194498Sbrooks pb_indices[i] = i; 181184588Sdfr 182193650Srwatson /* 183193650Srwatson * and for the imaginary "idle" process 184184588Sdfr */ 185177633Sdfr size = sizeof(ctimes); 186177633Sdfr sysctl(cp_time_mib, 2, &ctimes, &size, NULL, 0); 187184588Sdfr 188184588Sdfr t = 0; 189184588Sdfr for (i = 0; i < CPUSTATES; i++) 190184588Sdfr t += ctimes[i] - stime[i]; 191184588Sdfr if (t == 0.0) 192177633Sdfr t = 1.0; 193177633Sdfr 194177633Sdfr procbase[nproc].p_pctcpu = (ctimes[CP_IDLE] - stime[CP_IDLE]) / t / pctdouble(1); 195177633Sdfr for (i = 0; i < CPUSTATES; i++) 196177633Sdfr stime[i] = ctimes[i]; 197 198 qsort(pb_indices, nproc + 1, sizeof (int), compar); 199 200 pigs_cnt = 0; 201 for (k = 0; k < nproc + 1; k++) { 202 int j = pb_indices[k]; 203 if (pctdouble(procbase[j].p_pctcpu) < 0.01) 204 break; 205 pigs_cnt++; 206 } 207 208 num_disp = pigs_cnt; 209 return 0; 210} 211 212 213void 214print_pg(void) 215{ 216 int n, count = 0; 217 218 for (n = dispstart; n < num_disp; n++) { 219 showpigs(pb_indices[n]); 220 count++; 221 if (maxprint > 0 && count >= maxprint) 222 break; 223 } 224} 225 226int 227initpigs(void) 228{ 229 static int sysload_mib[] = {CTL_VM, VM_LOADAVG}; 230 static int cp_time_mib[] = { CTL_KERN, KERN_CPTIME }; 231 static int ccpu_mib[] = { CTL_KERN, KERN_CCPU }; 232 field_view *v; 233 size_t size; 234 fixpt_t ccpu; 235 236 size = sizeof(stime); 237 sysctl(cp_time_mib, 2, &stime, &size, NULL, 0); 238 239 size = sizeof(sysload); 240 sysctl(sysload_mib, 2, &sysload, &size, NULL, 0); 241 242 size = sizeof(ccpu); 243 sysctl(ccpu_mib, 2, &ccpu, &size, NULL, 0); 244 245 lccpu = log((double) ccpu / sysload.fscale); 246 247 for (v = views_pg; v->name != NULL; v++) 248 add_view(v); 249 250 return(1); 251} 252 253void 254showpigs(int k) 255{ 256 struct kinfo_proc *kp; 257 double value; 258 const char *uname, *pname; 259 260 if (procbase == NULL) 261 return; 262 263 value = pctdouble(procbase[k].p_pctcpu) * 100; 264 265 kp = &procbase[k]; 266 if (kp->p_comm[0] == '\0') { 267 uname = ""; 268 pname = "<idle>"; 269 } else { 270 uname = user_from_uid(kp->p_uid, 0); 271 pname = kp->p_comm; 272 print_fld_uint(FLD_PG_PID, kp->p_pid); 273 } 274 275 tb_start(); 276 tbprintf("%.2f", value); 277 print_fld_tb(FLD_PG_VALUE); 278 279 print_fld_str(FLD_PG_NAME, pname); 280 print_fld_str(FLD_PG_USER, uname); 281 print_fld_bar(FLD_PG_BAR, value); 282 283 end_line(); 284} 285 286 287int 288compar(const void *a, const void *b) 289{ 290 int i1 = *((int *)a); 291 int i2 = *((int *)b); 292 293 return procbase[i1].p_pctcpu > 294 procbase[i2].p_pctcpu ? -1 : 1; 295} 296 297