xref: /openbsd/usr.bin/systat/pigs.c (revision 4ec73a12)
1 /*	$OpenBSD: pigs.c,v 1.33 2022/02/22 17:35:01 deraadt 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/types.h>
38 #include <sys/signal.h>
39 #include <sys/proc.h>
40 #include <sys/resource.h>
41 #include <sys/sched.h>
42 #include <sys/sysctl.h>
43 #include <sys/time.h>
44 
45 #include <curses.h>
46 #include <math.h>
47 #include <pwd.h>
48 #include <err.h>
49 #include <stdlib.h>
50 #include <string.h>
51 
52 #include "systat.h"
53 
54 int compar(const void *, const void *);
55 void print_pg(void);
56 int read_pg(void);
57 int select_pg(void);
58 void showpigs(int k);
59 
60 static struct kinfo_proc *procbase = NULL;
61 static int nproc, pigs_cnt, *pb_indices = NULL;
62 static int onproc = -1;
63 
64 static long stime[CPUSTATES];
65 static double  lccpu;
66 struct loadavg sysload;
67 
68 
69 
70 field_def fields_pg[] = {
71 	{"USER", 6, 16, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
72 	{"NAME", 10, 24, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
73 	{"PID", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
74 	{"CPU", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
75 	{"", 30, 60, 1, FLD_ALIGN_BAR, -1, 0, 0, 100},
76 };
77 
78 #define FLD_PG_USER	FIELD_ADDR(fields_pg,0)
79 #define FLD_PG_NAME	FIELD_ADDR(fields_pg,1)
80 #define FLD_PG_PID	FIELD_ADDR(fields_pg,2)
81 #define FLD_PG_VALUE	FIELD_ADDR(fields_pg,3)
82 #define FLD_PG_BAR	FIELD_ADDR(fields_pg,4)
83 
84 /* Define views */
85 field_def *view_pg_0[] = {
86 	FLD_PG_PID, FLD_PG_USER, FLD_PG_NAME, FLD_PG_VALUE, FLD_PG_BAR, NULL
87 };
88 
89 
90 /* Define view managers */
91 struct view_manager pigs_mgr = {
92 	"Pigs", select_pg, read_pg, NULL, print_header,
93 	print_pg, keyboard_callback, NULL, NULL
94 };
95 
96 field_view views_pg[] = {
97 	{view_pg_0, "pigs", '5', &pigs_mgr},
98 	{NULL, NULL, 0, NULL}
99 };
100 
101 int	fscale;
102 
103 #define pctdouble(p) ((double)(p) / fscale)
104 
105 typedef long pctcpu;
106 
107 int
select_pg(void)108 select_pg(void)
109 {
110 	int mib[] = { CTL_KERN, KERN_FSCALE };
111 	size_t size = sizeof(fscale);
112 
113         if (sysctl(mib, sizeof(mib) / sizeof(mib[0]),
114             &fscale, &size, NULL, 0) == -1)
115                 return (-1);
116 	num_disp = pigs_cnt;
117 	return (0);
118 }
119 
120 
121 int
getprocs(void)122 getprocs(void)
123 {
124 	size_t size;
125 	int mib[6] = {CTL_KERN, KERN_PROC, KERN_PROC_KTHREAD, 0, sizeof(struct kinfo_proc), 0};
126 
127 	int st;
128 
129 	free(procbase);
130 	procbase = NULL;
131 
132 	st = sysctl(mib, 6, NULL, &size, NULL, 0);
133 	if (st == -1)
134 		return (1);
135 
136 	size = 5 * size / 4;		/* extra slop */
137 	if ((procbase = malloc(size + 1)) == NULL)
138 		return (1);
139 
140 	mib[5] = (int)(size / sizeof(struct kinfo_proc));
141 	st = sysctl(mib, 6, procbase, &size, NULL, 0);
142 	if (st == -1)
143 		return (1);
144 
145 	nproc = (int)(size / sizeof(struct kinfo_proc));
146 	return (0);
147 }
148 
149 
150 int
read_pg(void)151 read_pg(void)
152 {
153 	static int cp_time_mib[] = { CTL_KERN, KERN_CPTIME };
154 	long ctimes[CPUSTATES];
155 	double t;
156 	int i, k;
157 	size_t size;
158 
159 	num_disp = pigs_cnt = 0;
160 
161 	if (getprocs()) {
162 		error("Failed to read process info!");
163 		return 1;
164 	}
165 
166 	if (nproc > onproc) {
167 		int *p;
168 		p = reallocarray(pb_indices, nproc + 1, sizeof(int));
169 		if (p == NULL) {
170 			error("Out of Memory!");
171 			return 1;
172 		}
173 		pb_indices = p;
174 		onproc = nproc;
175 	}
176 
177 	memset(&procbase[nproc], 0, sizeof(*procbase));
178 
179 	for (i = 0; i <= nproc; i++)
180 		pb_indices[i] = i;
181 
182 	/*
183 	 * and for the imaginary "idle" process
184 	 */
185 	size = sizeof(ctimes);
186 	sysctl(cp_time_mib, 2, &ctimes, &size, NULL, 0);
187 
188 	t = 0;
189 	for (i = 0; i < CPUSTATES; i++)
190 		t += ctimes[i] - stime[i];
191 	if (t == 0.0)
192 		t = 1.0;
193 
194 	procbase[nproc].p_pctcpu = (ctimes[CP_IDLE] - stime[CP_IDLE]) / t / pctdouble(1);
195 	for (i = 0; i < CPUSTATES; i++)
196 		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 
213 void
print_pg(void)214 print_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 
226 int
initpigs(void)227 initpigs(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 
253 void
showpigs(int k)254 showpigs(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 
287 int
compar(const void * a,const void * b)288 compar(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