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