xref: /openbsd-src/usr.bin/systat/pigs.c (revision 50b7afb2c2c0993b0894d4e34bf857cb13ed9c80)
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