xref: /original-bsd/usr.bin/systat/pigs.c (revision 93152bbe)
1 /*
2  * Copyright (c) 1980 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 static char sccsid[] = "@(#)pigs.c	5.9 (Berkeley) 06/26/91";
9 #endif not lint
10 
11 /*
12  * Pigs display from Bill Reeves at Lucasfilm
13  */
14 
15 #include "systat.h"
16 #include <sys/dir.h>
17 #include <sys/time.h>
18 #include <sys/proc.h>
19 #include <sys/kinfo.h>
20 #include <sys/kinfo_proc.h>
21 #include <pwd.h>
22 #include <kvm.h>
23 
24 struct p_times {
25 	float   pt_pctcpu;
26 	struct  proc *pt_pp;
27 } *pt;
28 int	ptsize;
29 int	nproc;
30 int     fscale;
31 double  lccpu;
32 
33 
34 WINDOW *
35 openpigs()
36 {
37 	return (subwin(stdscr, LINES-5-1, 0, 5, 0));
38 }
39 
40 closepigs(w)
41 	WINDOW *w;
42 {
43 	if (w == NULL)
44 		return;
45 	wclear(w);
46 	wrefresh(w);
47 	delwin(w);
48 }
49 
50 int	maxind;
51 int     factor;
52 float   total;
53 char    pidname[30];
54 long	stime[CPUSTATES];
55 
56 showpigs()
57 {
58 	register short auid;
59 	register int i, j, y;
60 	register float max;
61 	register struct p_times *ptptr;
62 	struct	p_times temppt;
63 	struct	eproc *ep;
64 	char *uname, *pname;
65 
66 	if (pt == NULL)
67 		return;
68 	/* Accumulate the percent of cpu per user. */
69 	ptptr = pt;
70 	total = 0.0;
71 	for (i = 0; i < nproc; i++) {
72 		/* Accumulate the percentage. */
73 		total += ptptr->pt_pctcpu;
74 		ptptr++;
75 	}
76 
77 	total += pt[nproc].pt_pctcpu;	/* idle "process" */
78 
79 	if (total < 1.0)
80 		total = 1.0;
81 	factor = 50.0/total;
82 
83 	/* Find the top few by executing a "bubble pass" ten times. */
84 	y = nproc + 1;
85 	if (y > wnd->_maxy-1)
86 		y = wnd->_maxy-1;
87 	for (i = 0; i < y; i++) {
88 		ptptr = &pt[i];
89 		max = -10000.0;
90 		maxind = i;
91 		for (j = i; j < nproc + 1; j++) {
92 			if (ptptr->pt_pctcpu > max) {
93 				max = ptptr->pt_pctcpu;
94 				maxind = j;
95 			}
96 			ptptr++;
97 		}
98 		if (maxind != i) {
99 			temppt = pt[i];
100 			pt[i] = pt[maxind];
101 			pt[maxind] = temppt;
102 		}
103 	}
104 	y = 1;
105 	ptptr = pt;
106 	i = nproc + 1;
107 	if (i > wnd->_maxy-1)
108 		i = wnd->_maxy-1;
109 	for (; i > 0 && ptptr->pt_pctcpu > 0.01; i--, y++, ptptr++) {
110 		if (ptptr->pt_pp == NULL) {
111 			uname = "";
112 			pname = "<idle>";
113 		}
114 		else {
115 			ep = kvm_geteproc(ptptr->pt_pp);
116 			uname = (char *)user_from_uid(ep->e_ucred.cr_uid, 0);
117 			pname = ptptr->pt_pp->p_comm;
118 		}
119 		wmove(wnd, y, 0);
120 		wclrtoeol(wnd);
121 		mvwaddstr(wnd, y, 0, uname);
122 		sprintf(pidname, "%10.10s", pname, 0);
123 		mvwaddstr(wnd, y, 9, pidname);
124 		wmove(wnd, y, 20);
125 		for (j = ptptr->pt_pctcpu*factor + 0.5; j > 0; j--)
126 			waddch(wnd, 'X');
127 	}
128 	wmove(wnd, y, 0); wclrtobot(wnd);
129 }
130 
131 static struct nlist nlst[] = {
132 #define X_FIRST		0
133 #define X_CPTIME	0
134 	{ "_cp_time" },
135 #define X_CCPU          1
136 	{ "_ccpu" },
137 #define X_FSCALE        2
138 	{ "_fscale" },
139 
140 	{ "" }
141 };
142 
143 initpigs()
144 {
145 	fixpt_t ccpu;
146 
147 	if (nlst[X_FIRST].n_type == 0) {
148 		kvm_nlist(nlst);
149 		if (nlst[X_FIRST].n_type == 0) {
150 			error("namelist failed");
151 			return(0);
152 		}
153 	}
154 	KREAD(NPTR(X_CPTIME), stime, sizeof (stime));
155 	NREAD(X_CCPU, &ccpu, LONG);
156 	NREAD(X_FSCALE,  &fscale, LONG);
157 	lccpu = log((double) ccpu / fscale);
158 
159 	return(1);
160 }
161 
162 fetchpigs()
163 {
164 	register int i;
165 	register struct p_times *prt;
166 	register float time;
167 	register struct proc *pp;
168 	long ctime[CPUSTATES];
169 	double t;
170 
171 	if (nlst[X_FIRST].n_type == 0)
172 		return;
173 	kvm_freeprocs();	/* clear previous buffer */
174 	if ((nproc = kvm_getprocs(KINFO_PROC_ALL, 0)) == -1) {
175 		error("%s", kvm_geterr());
176 		if (pt)
177 			free(pt);
178 		ptsize = 0;
179 		return;
180 	}
181 	/*
182 	 * The nproc + 1'th entry is for the imaginary "idle"
183 	 * process to which we attribute the unused part of the cpu
184 	 */
185 	if ((nproc + 1) * sizeof (struct p_times) > ptsize) {
186 		if (pt)
187 			free(pt);
188 		ptsize = (nproc + 1) * sizeof (struct p_times);
189 		if ((pt = (struct p_times *)malloc(ptsize)) == NULL) {
190 			error("out of memory");
191 			die();
192 		}
193 	}
194 	/*
195 	 * calculate %cpu for each proc
196 	 */
197 	for (prt = pt; (pp = kvm_nextproc()) != NULL; prt++) {
198 		prt->pt_pp = pp;
199 		time = pp->p_time;
200 		if (time == 0 || (pp->p_flag & SLOAD) == 0)
201 			prt->pt_pctcpu = 0;
202 		else
203 			prt->pt_pctcpu = ((double) pp->p_pctcpu /
204 					fscale) / (1.0 - exp(time * lccpu));
205 	}
206 	/*
207 	 * and for the imaginary "idle" process, pt[nproc]
208 	 */
209 	KREAD(NPTR(X_CPTIME), ctime, sizeof (ctime));
210 	t = 0;
211 	for (i = 0; i < CPUSTATES; i++)
212 		t += ctime[i] - stime[i];
213 	if (t == 0.0)
214 		t = 1.0;
215 	pt[nproc].pt_pp = NULL;
216 	pt[nproc].pt_pctcpu = (ctime[CP_IDLE] - stime[CP_IDLE]) / t;
217 	for (i = 0; i < CPUSTATES; i++)
218 		stime[i] = ctime[i];
219 }
220 
221 labelpigs()
222 {
223 	wmove(wnd, 0, 0); wclrtoeol(wnd);
224 	mvwaddstr(wnd, 0, 20,
225 	    "/0   /10  /20  /30  /40  /50  /60  /70  /80  /90  /100");
226 }
227