xref: /openbsd/usr.bin/systat/pool.c (revision cecf84d4)
1 /*	$OpenBSD: pool.c,v 1.10 2015/01/16 00:03:37 deraadt Exp $	*/
2 /*
3  * Copyright (c) 2008 Can Erkin Acar <canacar@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/types.h>
19 #include <sys/signal.h>
20 #include <sys/sysctl.h>
21 #include <sys/pool.h>
22 #include <errno.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <limits.h>
26 
27 #include "systat.h"
28 
29 void print_pool(void);
30 int  read_pool(void);
31 void  sort_pool(void);
32 int  select_pool(void);
33 void showpool(int k);
34 int pool_keyboard_callback(int);
35 
36 /* qsort callbacks */
37 int sort_name_callback(const void *s1, const void *s2);
38 int sort_req_callback(const void *s1, const void *s2);
39 int sort_psize_callback(const void *s1, const void *s2);
40 int sort_npage_callback(const void *s1, const void *s2);
41 
42 struct pool_info {
43 	char name[32];
44 	struct kinfo_pool pool;
45 };
46 
47 
48 int print_all = 0;
49 int num_pools = 0;
50 struct pool_info *pools = NULL;
51 
52 
53 field_def fields_pool[] = {
54 	{"NAME", 11, 32, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
55 	{"SIZE", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
56 	{"REQUESTS", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
57 	{"FAIL", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
58 	{"INUSE", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
59 	{"PGREQ", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
60 	{"PGREL", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
61 	{"NPAGE", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
62 	{"HIWAT", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
63 	{"MINPG", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
64 	{"MAXPG", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
65 	{"IDLE", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}
66 };
67 
68 
69 #define FLD_POOL_NAME	FIELD_ADDR(fields_pool,0)
70 #define FLD_POOL_SIZE	FIELD_ADDR(fields_pool,1)
71 #define FLD_POOL_REQS	FIELD_ADDR(fields_pool,2)
72 #define FLD_POOL_FAIL	FIELD_ADDR(fields_pool,3)
73 #define FLD_POOL_INUSE	FIELD_ADDR(fields_pool,4)
74 #define FLD_POOL_PGREQ	FIELD_ADDR(fields_pool,5)
75 #define FLD_POOL_PGREL	FIELD_ADDR(fields_pool,6)
76 #define FLD_POOL_NPAGE	FIELD_ADDR(fields_pool,7)
77 #define FLD_POOL_HIWAT	FIELD_ADDR(fields_pool,8)
78 #define FLD_POOL_MINPG	FIELD_ADDR(fields_pool,9)
79 #define FLD_POOL_MAXPG	FIELD_ADDR(fields_pool,10)
80 #define FLD_POOL_IDLE	FIELD_ADDR(fields_pool,11)
81 
82 /* Define views */
83 field_def *view_pool_0[] = {
84 	FLD_POOL_NAME, FLD_POOL_SIZE, FLD_POOL_REQS, FLD_POOL_FAIL,
85 	FLD_POOL_INUSE, FLD_POOL_PGREQ, FLD_POOL_PGREL, FLD_POOL_NPAGE,
86 	FLD_POOL_HIWAT, FLD_POOL_MINPG, FLD_POOL_MAXPG, FLD_POOL_IDLE, NULL
87 };
88 
89 order_type pool_order_list[] = {
90 	{"name", "name", 'N', sort_name_callback},
91 	{"requests", "requests", 'Q', sort_req_callback},
92 	{"size", "size", 'Z', sort_psize_callback},
93 	{"npages", "npages", 'P', sort_npage_callback},
94 	{NULL, NULL, 0, NULL}
95 };
96 
97 /* Define view managers */
98 struct view_manager pool_mgr = {
99 	"Pool", select_pool, read_pool, sort_pool, print_header,
100 	print_pool, pool_keyboard_callback, pool_order_list, pool_order_list
101 };
102 
103 field_view views_pool[] = {
104 	{view_pool_0, "pool", '5', &pool_mgr},
105 	{NULL, NULL, 0, NULL}
106 };
107 
108 
109 int
110 sort_name_callback(const void *s1, const void *s2)
111 {
112 	struct pool_info *p1, *p2;
113 	p1 = (struct pool_info *)s1;
114 	p2 = (struct pool_info *)s2;
115 
116 	return strcmp(p1->name, p2->name) * sortdir;
117 }
118 
119 int
120 sort_req_callback(const void *s1, const void *s2)
121 {
122 	struct pool_info *p1, *p2;
123 	p1 = (struct pool_info *)s1;
124 	p2 = (struct pool_info *)s2;
125 
126 	if (p1->pool.pr_nget <  p2->pool.pr_nget)
127 		return sortdir;
128 	if (p1->pool.pr_nget >  p2->pool.pr_nget)
129 		return -sortdir;
130 
131 	return sort_name_callback(s1, s2);
132 }
133 
134 int
135 sort_npage_callback(const void *s1, const void *s2)
136 {
137 	struct pool_info *p1, *p2;
138 	p1 = (struct pool_info *)s1;
139 	p2 = (struct pool_info *)s2;
140 
141 	if (p1->pool.pr_npages <  p2->pool.pr_npages)
142 		return sortdir;
143 	if (p1->pool.pr_npages >  p2->pool.pr_npages)
144 		return -sortdir;
145 
146 	return sort_name_callback(s1, s2);
147 }
148 
149 int
150 sort_psize_callback(const void *s1, const void *s2)
151 {
152 	struct pool_info *p1, *p2;
153 	size_t ps1, ps2;
154 
155 	p1 = (struct pool_info *)s1;
156 	p2 = (struct pool_info *)s2;
157 
158 	ps1  = (size_t)(p1->pool.pr_nget - p1->pool.pr_nput) *
159 	    (size_t)p1->pool.pr_size;
160 	ps2  = (size_t)(p2->pool.pr_nget - p2->pool.pr_nput) *
161 	    (size_t)p2->pool.pr_size;
162 
163 	if (ps1 <  ps2)
164 		return sortdir;
165 	if (ps1 >  ps2)
166 		return -sortdir;
167 
168 	return sort_npage_callback(s1, s2);
169 }
170 
171 void
172 sort_pool(void)
173 {
174 	order_type *ordering;
175 
176 	if (curr_mgr == NULL)
177 		return;
178 
179 	ordering = curr_mgr->order_curr;
180 
181 	if (ordering == NULL)
182 		return;
183 	if (ordering->func == NULL)
184 		return;
185 	if (pools == NULL)
186 		return;
187 	if (num_pools <= 0)
188 		return;
189 
190 	mergesort(pools, num_pools, sizeof(struct pool_info), ordering->func);
191 }
192 
193 int
194 select_pool(void)
195 {
196 	num_disp = num_pools;
197 	return (0);
198 }
199 
200 int
201 read_pool(void)
202 {
203 	int mib[4], np, i;
204 	size_t size;
205 
206 	mib[0] = CTL_KERN;
207 	mib[1] = KERN_POOL;
208 	mib[2] = KERN_POOL_NPOOLS;
209 	size = sizeof(np);
210 
211 	if (sysctl(mib, 3, &np, &size, NULL, 0) < 0) {
212 		error("sysctl(npools): %s", strerror(errno));
213 		return (-1);
214 	}
215 
216 	if (np <= 0) {
217 		num_pools = 0;
218 		return (0);
219 	}
220 
221 	if (np > num_pools || pools == NULL) {
222 		struct pool_info *p = reallocarray(pools, np, sizeof(*pools));
223 		if (p == NULL) {
224 			error("realloc: %s", strerror(errno));
225 			return (-1);
226 		}
227 		pools = p;
228 		num_pools = np;
229 	}
230 
231 	num_disp = num_pools;
232 
233 	for (i = 0; i < num_pools; i++) {
234 		mib[0] = CTL_KERN;
235 		mib[1] = KERN_POOL;
236 		mib[2] = KERN_POOL_POOL;
237 		mib[3] = i + 1;
238 		size = sizeof(pools[i].pool);
239 		if (sysctl(mib, 4, &pools[i].pool, &size, NULL, 0) < 0) {
240 			memset(&pools[i], 0, sizeof(pools[i]));
241 			num_disp--;
242 			continue;
243 		}
244 		mib[2] = KERN_POOL_NAME;
245 		size = sizeof(pools[i].name);
246 		if (sysctl(mib, 4, &pools[i].name, &size, NULL, 0) < 0) {
247 			snprintf(pools[i].name, size, "#%d#", mib[3]);
248 		}
249 	}
250 
251 	if (i != num_pools) {
252 		memset(pools, 0, sizeof(*pools) * num_pools);
253 		return (-1);
254 	}
255 
256 	return 0;
257 }
258 
259 
260 void
261 print_pool(void)
262 {
263 	struct pool_info *p;
264 	int i, n, count = 0;
265 
266 	if (pools == NULL)
267 		return;
268 
269 	for (n = i = 0; i < num_pools; i++) {
270 		p = &pools[i];
271 		if (p->name[0] == 0)
272 			continue;
273 
274 		if (!print_all &&
275 		   (p->pool.pr_nget == 0 && p->pool.pr_npagealloc == 0))
276 			continue;
277 
278 		if (n++ < dispstart)
279 			continue;
280 		showpool(i);
281 		count++;
282 		if (maxprint > 0 && count >= maxprint)
283 			break;
284 	}
285 }
286 
287 int
288 initpool(void)
289 {
290 	field_view *v;
291 
292 	for (v = views_pool; v->name != NULL; v++)
293 		add_view(v);
294 
295 	read_pool();
296 
297 	return(0);
298 }
299 
300 void
301 showpool(int k)
302 {
303 	struct pool_info *p = pools + k;
304 
305 	if (k < 0 || k >= num_pools)
306 		return;
307 
308 	print_fld_str(FLD_POOL_NAME, p->name);
309 	print_fld_uint(FLD_POOL_SIZE, p->pool.pr_size);
310 
311 	print_fld_size(FLD_POOL_REQS, p->pool.pr_nget);
312 	print_fld_size(FLD_POOL_FAIL, p->pool.pr_nfail);
313 	print_fld_ssize(FLD_POOL_INUSE, p->pool.pr_nget - p->pool.pr_nput);
314 	print_fld_size(FLD_POOL_PGREQ, p->pool.pr_npagealloc);
315 	print_fld_size(FLD_POOL_PGREL, p->pool.pr_npagefree);
316 
317 	print_fld_size(FLD_POOL_NPAGE, p->pool.pr_npages);
318 	print_fld_size(FLD_POOL_HIWAT, p->pool.pr_hiwat);
319 	print_fld_size(FLD_POOL_MINPG, p->pool.pr_minpages);
320 
321 	if (p->pool.pr_maxpages == UINT_MAX)
322 		print_fld_str(FLD_POOL_MAXPG, "inf");
323 	else
324 		print_fld_size(FLD_POOL_MAXPG, p->pool.pr_maxpages);
325 
326 	print_fld_size(FLD_POOL_IDLE, p->pool.pr_nidle);
327 
328 	end_line();
329 }
330 
331 int
332 pool_keyboard_callback(int ch)
333 {
334 	switch (ch) {
335 	case 'A':
336 		print_all ^= 1;
337 		gotsig_alarm = 1;
338 	default:
339 		return keyboard_callback(ch);
340 	};
341 
342 	return (1);
343 }
344