xref: /openbsd/usr.bin/systat/pigs.c (revision 404b540a)
1 /*	$OpenBSD: pigs.c,v 1.23 2008/12/07 02:56:06 canacar 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/dir.h>
41 #include <sys/time.h>
42 #include <sys/proc.h>
43 #include <sys/sysctl.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_proc2 *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 FIELD_ADDR(x) (&fields_pg[x])
79 
80 #define FLD_PG_USER	FIELD_ADDR(0)
81 #define FLD_PG_NAME	FIELD_ADDR(1)
82 #define FLD_PG_PID	FIELD_ADDR(2)
83 #define FLD_PG_VALUE	FIELD_ADDR(3)
84 #define FLD_PG_BAR	FIELD_ADDR(4)
85 
86 /* Define views */
87 field_def *view_pg_0[] = {
88 	FLD_PG_PID, FLD_PG_USER, FLD_PG_NAME, FLD_PG_VALUE, FLD_PG_BAR, NULL
89 };
90 
91 
92 /* Define view managers */
93 struct view_manager pigs_mgr = {
94 	"Pigs", select_pg, read_pg, NULL, print_header,
95 	print_pg, keyboard_callback, NULL, NULL
96 };
97 
98 field_view views_pg[] = {
99 	{view_pg_0, "pigs", '5', &pigs_mgr},
100 	{NULL, NULL, 0, NULL}
101 };
102 
103 
104 #ifdef FSCALE
105 # define FIXED_LOADAVG FSCALE
106 # define FIXED_PCTCPU FSCALE
107 #endif
108 
109 #ifdef FIXED_PCTCPU
110   typedef long pctcpu;
111 # define pctdouble(p) ((double)(p) / FIXED_PCTCPU)
112 #else
113 typedef double pctcpu;
114 # define pctdouble(p) (p)
115 #endif
116 
117 int
118 select_pg(void)
119 {
120 	num_disp = pigs_cnt;
121 	return (0);
122 }
123 
124 
125 int
126 getprocs(void)
127 {
128 	size_t size;
129 	int mib[6] = {CTL_KERN, KERN_PROC2, KERN_PROC_KTHREAD, 0, sizeof(struct kinfo_proc2), 0};
130 
131 	int st;
132 
133 	free(procbase);
134 	procbase = NULL;
135 
136 	st = sysctl(mib, 6, NULL, &size, NULL, 0);
137 	if (st == -1)
138 		return (1);
139 
140 	size = 5 * size / 4;		/* extra slop */
141 	if ((procbase = malloc(size + 1)) == NULL)
142 		return (1);
143 
144 	mib[5] = (int)(size / sizeof(struct kinfo_proc2));
145 	st = sysctl(mib, 6, procbase, &size, NULL, 0);
146 	if (st == -1)
147 		return (1);
148 
149 	nproc = (int)(size / sizeof(struct kinfo_proc2));
150 	return (0);
151 }
152 
153 
154 int
155 read_pg(void)
156 {
157 	static int cp_time_mib[] = { CTL_KERN, KERN_CPTIME };
158 	long ctimes[CPUSTATES];
159 	double t;
160 	int i, k;
161 	size_t size;
162 
163 	num_disp = pigs_cnt = 0;
164 
165 	if (getprocs()) {
166 		error("Failed to read process info!");
167 		return 1;
168 	}
169 
170 	if (nproc > onproc) {
171 		int *p;
172 		p = realloc(pb_indices, (nproc + 1) * sizeof(int));
173 		if (p == NULL) {
174 			error("Out of Memory!");
175 			return 1;
176 		}
177 		pb_indices = p;
178 		onproc = nproc;
179 	}
180 
181 	memset(&procbase[nproc], 0, sizeof(*procbase));
182 
183 	for (i = 0; i <= nproc; i++)
184 		pb_indices[i] = i;
185 
186 	/*
187 	 * and for the imaginary "idle" process
188 	 */
189 	size = sizeof(ctimes);
190 	sysctl(cp_time_mib, 2, &ctimes, &size, NULL, 0);
191 
192 	t = 0;
193 	for (i = 0; i < CPUSTATES; i++)
194 		t += ctimes[i] - stime[i];
195 	if (t == 0.0)
196 		t = 1.0;
197 
198 	procbase[nproc].p_pctcpu = (ctimes[CP_IDLE] - stime[CP_IDLE]) / t / pctdouble(1);
199 	for (i = 0; i < CPUSTATES; i++)
200 		stime[i] = ctimes[i];
201 
202 	qsort(pb_indices, nproc + 1, sizeof (int), compar);
203 
204 	pigs_cnt = 0;
205 	for (k = 0; k < nproc + 1; k++) {
206 		int j = pb_indices[k];
207 		if (pctdouble(procbase[j].p_pctcpu) < 0.01)
208 			break;
209 		pigs_cnt++;
210 	}
211 
212 	num_disp = pigs_cnt;
213 	return 0;
214 }
215 
216 
217 void
218 print_pg(void)
219 {
220 	int n, count = 0;
221 
222 	for (n = dispstart; n < num_disp; n++) {
223 		showpigs(pb_indices[n]);
224 		count++;
225 		if (maxprint > 0 && count >= maxprint)
226 			break;
227 	}
228 }
229 
230 int
231 initpigs(void)
232 {
233 	static int sysload_mib[] = {CTL_VM, VM_LOADAVG};
234 	static int cp_time_mib[] = { CTL_KERN, KERN_CPTIME };
235 	static int ccpu_mib[] = { CTL_KERN, KERN_CCPU };
236 	field_view *v;
237 	size_t size;
238 	fixpt_t ccpu;
239 
240 	size = sizeof(stime);
241 	sysctl(cp_time_mib, 2, &stime, &size, NULL, 0);
242 
243 	size = sizeof(sysload);
244 	sysctl(sysload_mib, 2, &sysload, &size, NULL, 0);
245 
246 	size = sizeof(ccpu);
247 	sysctl(ccpu_mib, 2, &ccpu, &size, NULL, 0);
248 
249 	lccpu = log((double) ccpu / sysload.fscale);
250 
251 	for (v = views_pg; v->name != NULL; v++)
252 		add_view(v);
253 
254 	return(1);
255 }
256 
257 void
258 showpigs(int k)
259 {
260 	struct kinfo_proc2 *kp;
261 	double value;
262 	char *uname, *pname;
263 
264 	if (procbase == NULL)
265 		return;
266 
267 	value = pctdouble(procbase[k].p_pctcpu) * 100;
268 
269 	kp = &procbase[k];
270 	if (kp->p_comm[0] == '\0') {
271 		uname = "";
272 		pname = "<idle>";
273 	} else {
274 		uname = user_from_uid(kp->p_uid, 0);
275 		pname = kp->p_comm;
276 		print_fld_uint(FLD_PG_PID, kp->p_pid);
277 	}
278 
279 	tb_start();
280 	tbprintf("%.2f", value);
281 	print_fld_tb(FLD_PG_VALUE);
282 
283 	print_fld_str(FLD_PG_NAME, pname);
284 	print_fld_str(FLD_PG_USER, uname);
285 	print_fld_bar(FLD_PG_BAR, value);
286 
287 	end_line();
288 }
289 
290 
291 int
292 compar(const void *a, const void *b)
293 {
294 	int i1 = *((int *)a);
295 	int i2 = *((int *)b);
296 
297 	return procbase[i1].p_pctcpu >
298 		procbase[i2].p_pctcpu ? -1 : 1;
299 }
300 
301