GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/systat/pool.c Lines: 0 197 0.0 %
Date: 2017-11-13 Branches: 0 110 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: pool.c,v 1.15 2017/07/31 04:23:30 dlg 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
#ifndef nitems
30
#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
31
#endif
32
33
static int sysctl_rdint(const int *, unsigned int);
34
static int hw_ncpusfound(void);
35
36
static int pool_get_npools(void);
37
static int pool_get_name(int, char *, size_t);
38
static int pool_get_cache(int, struct kinfo_pool_cache *);
39
static int pool_get_cache_cpus(int, struct kinfo_pool_cache_cpu *,
40
    unsigned int);
41
42
void print_pool(void);
43
int  read_pool(void);
44
void  sort_pool(void);
45
int  select_pool(void);
46
void showpool(int k);
47
int pool_keyboard_callback(int);
48
49
/* qsort callbacks */
50
int sort_name_callback(const void *s1, const void *s2);
51
int sort_req_callback(const void *s1, const void *s2);
52
int sort_psize_callback(const void *s1, const void *s2);
53
int sort_npage_callback(const void *s1, const void *s2);
54
55
struct pool_info {
56
	char name[32];
57
	struct kinfo_pool pool;
58
};
59
60
/*
61
 * the kernel gives an array of ncpusfound * kinfo_pool_cache structs, but
62
 * it's idea of how big that struct is may differ from here. we fetch both
63
 * ncpusfound and the size it thinks kinfo_pool_cache is from sysctl, and
64
 * then allocate the memory for this here.
65
 */
66
struct pool_cache_info {
67
	char name[32];
68
	struct kinfo_pool_cache cache;
69
	struct kinfo_pool_cache_cpu *cache_cpus;
70
};
71
72
int print_all = 0;
73
int num_pools = 0;
74
struct pool_info *pools = NULL;
75
int num_pool_caches = 0;
76
struct pool_cache_info *pool_caches = NULL;
77
78
int ncpusfound = 0;
79
80
field_def fields_pool[] = {
81
	{"NAME", 12, 32, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
82
	{"SIZE", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
83
	{"REQUESTS", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
84
	{"FAIL", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
85
	{"INUSE", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
86
	{"PGREQ", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
87
	{"PGREL", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
88
	{"NPAGE", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
89
	{"HIWAT", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
90
	{"MINPG", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
91
	{"MAXPG", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
92
	{"IDLE", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}
93
};
94
95
#define FLD_POOL_NAME	FIELD_ADDR(fields_pool,0)
96
#define FLD_POOL_SIZE	FIELD_ADDR(fields_pool,1)
97
#define FLD_POOL_REQS	FIELD_ADDR(fields_pool,2)
98
#define FLD_POOL_FAIL	FIELD_ADDR(fields_pool,3)
99
#define FLD_POOL_INUSE	FIELD_ADDR(fields_pool,4)
100
#define FLD_POOL_PGREQ	FIELD_ADDR(fields_pool,5)
101
#define FLD_POOL_PGREL	FIELD_ADDR(fields_pool,6)
102
#define FLD_POOL_NPAGE	FIELD_ADDR(fields_pool,7)
103
#define FLD_POOL_HIWAT	FIELD_ADDR(fields_pool,8)
104
#define FLD_POOL_MINPG	FIELD_ADDR(fields_pool,9)
105
#define FLD_POOL_MAXPG	FIELD_ADDR(fields_pool,10)
106
#define FLD_POOL_IDLE	FIELD_ADDR(fields_pool,11)
107
108
/* Define views */
109
field_def *view_pool_0[] = {
110
	FLD_POOL_NAME, FLD_POOL_SIZE, FLD_POOL_REQS, FLD_POOL_FAIL,
111
	FLD_POOL_INUSE, FLD_POOL_PGREQ, FLD_POOL_PGREL, FLD_POOL_NPAGE,
112
	FLD_POOL_HIWAT, FLD_POOL_MINPG, FLD_POOL_MAXPG, FLD_POOL_IDLE, NULL
113
};
114
115
order_type pool_order_list[] = {
116
	{"name", "name", 'N', sort_name_callback},
117
	{"requests", "requests", 'Q', sort_req_callback},
118
	{"size", "size", 'Z', sort_psize_callback},
119
	{"npages", "npages", 'P', sort_npage_callback},
120
	{NULL, NULL, 0, NULL}
121
};
122
123
/* Define view managers */
124
struct view_manager pool_mgr = {
125
	"Pool", select_pool, read_pool, sort_pool, print_header,
126
	print_pool, pool_keyboard_callback, pool_order_list, pool_order_list
127
};
128
129
field_view pool_view = {
130
	view_pool_0,
131
	"pool",
132
	'5',
133
	&pool_mgr
134
};
135
136
void	pool_cache_print(void);
137
int	pool_cache_read(void);
138
void	pool_cache_sort(void);
139
void	pool_cache_show(const struct pool_cache_info *);
140
int	pool_cache_kbd_cb(int);
141
142
field_def pool_cache_fields[] = {
143
	{"NAME", 12, 32, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
144
	{"LEN", 4, 4, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
145
	{"IDLE", 4, 4, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
146
	{"NGC", 4, 4, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
147
	{"CPU",  4, 4, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
148
	{"REQ", 8, 12, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
149
	{"REL", 8, 12, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
150
	{"LREQ", 8, 12, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
151
	{"LREL", 8, 12, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
152
};
153
154
#define FLD_POOL_CACHE_NAME	FIELD_ADDR(pool_cache_fields, 0)
155
#define FLD_POOL_CACHE_LEN	FIELD_ADDR(pool_cache_fields, 1)
156
#define FLD_POOL_CACHE_IDLE	FIELD_ADDR(pool_cache_fields, 2)
157
#define FLD_POOL_CACHE_NGC	FIELD_ADDR(pool_cache_fields, 3)
158
#define FLD_POOL_CACHE_CPU	FIELD_ADDR(pool_cache_fields, 4)
159
#define FLD_POOL_CACHE_GET	FIELD_ADDR(pool_cache_fields, 5)
160
#define FLD_POOL_CACHE_PUT	FIELD_ADDR(pool_cache_fields, 6)
161
#define FLD_POOL_CACHE_LGET	FIELD_ADDR(pool_cache_fields, 7)
162
#define FLD_POOL_CACHE_LPUT	FIELD_ADDR(pool_cache_fields, 8)
163
164
field_def *view_pool_cache_0[] = {
165
	FLD_POOL_CACHE_NAME,
166
	FLD_POOL_CACHE_LEN,
167
	FLD_POOL_CACHE_IDLE,
168
	FLD_POOL_CACHE_NGC,
169
	FLD_POOL_CACHE_CPU,
170
	FLD_POOL_CACHE_GET,
171
	FLD_POOL_CACHE_PUT,
172
	FLD_POOL_CACHE_LGET,
173
	FLD_POOL_CACHE_LPUT,
174
	NULL,
175
};
176
177
order_type pool_cache_order_list[] = {
178
	{"name", "name", 'N', sort_name_callback},
179
	{"requests", "requests", 'G', sort_req_callback},
180
	{"releases", "releases", 'P', sort_req_callback},
181
	{NULL, NULL, 0, NULL}
182
};
183
184
/* Define view managers */
185
struct view_manager pool_cache_mgr = {
186
	"PoolCache",
187
	select_pool,
188
	pool_cache_read,
189
	pool_cache_sort,
190
	print_header,
191
	pool_cache_print,
192
	pool_keyboard_callback,
193
	pool_cache_order_list,
194
	pool_cache_order_list
195
};
196
197
field_view pool_cache_view = {
198
	view_pool_cache_0,
199
	"pcaches",
200
	'5',
201
	&pool_cache_mgr
202
};
203
204
int
205
sort_name_callback(const void *s1, const void *s2)
206
{
207
	struct pool_info *p1, *p2;
208
	p1 = (struct pool_info *)s1;
209
	p2 = (struct pool_info *)s2;
210
211
	return strcmp(p1->name, p2->name) * sortdir;
212
}
213
214
int
215
sort_req_callback(const void *s1, const void *s2)
216
{
217
	struct pool_info *p1, *p2;
218
	p1 = (struct pool_info *)s1;
219
	p2 = (struct pool_info *)s2;
220
221
	if (p1->pool.pr_nget <  p2->pool.pr_nget)
222
		return sortdir;
223
	if (p1->pool.pr_nget >  p2->pool.pr_nget)
224
		return -sortdir;
225
226
	return sort_name_callback(s1, s2);
227
}
228
229
int
230
sort_npage_callback(const void *s1, const void *s2)
231
{
232
	struct pool_info *p1, *p2;
233
	p1 = (struct pool_info *)s1;
234
	p2 = (struct pool_info *)s2;
235
236
	if (p1->pool.pr_npages <  p2->pool.pr_npages)
237
		return sortdir;
238
	if (p1->pool.pr_npages >  p2->pool.pr_npages)
239
		return -sortdir;
240
241
	return sort_name_callback(s1, s2);
242
}
243
244
int
245
sort_psize_callback(const void *s1, const void *s2)
246
{
247
	struct pool_info *p1, *p2;
248
	size_t ps1, ps2;
249
250
	p1 = (struct pool_info *)s1;
251
	p2 = (struct pool_info *)s2;
252
253
	ps1  = (size_t)(p1->pool.pr_nget - p1->pool.pr_nput) *
254
	    (size_t)p1->pool.pr_size;
255
	ps2  = (size_t)(p2->pool.pr_nget - p2->pool.pr_nput) *
256
	    (size_t)p2->pool.pr_size;
257
258
	if (ps1 <  ps2)
259
		return sortdir;
260
	if (ps1 >  ps2)
261
		return -sortdir;
262
263
	return sort_npage_callback(s1, s2);
264
}
265
266
void
267
sort_pool(void)
268
{
269
	order_type *ordering;
270
271
	if (curr_mgr == NULL)
272
		return;
273
274
	ordering = curr_mgr->order_curr;
275
276
	if (ordering == NULL)
277
		return;
278
	if (ordering->func == NULL)
279
		return;
280
	if (pools == NULL)
281
		return;
282
	if (num_pools <= 0)
283
		return;
284
285
	mergesort(pools, num_pools, sizeof(struct pool_info), ordering->func);
286
}
287
288
int
289
select_pool(void)
290
{
291
	num_disp = num_pools;
292
	return (0);
293
}
294
295
int
296
read_pool(void)
297
{
298
	int mib[] = { CTL_KERN, KERN_POOL, KERN_POOL_POOL, 0 };
299
	struct pool_info *p;
300
	int np, i;
301
	size_t size;
302
303
	np = pool_get_npools();
304
	if (np == -1) {
305
		error("sysctl(npools): %s", strerror(errno));
306
		return (-1);
307
	}
308
309
	if (np == 0) {
310
		free(pools);
311
		pools = NULL;
312
		num_pools = 0;
313
		return (0);
314
	}
315
316
	if (np > num_pools || pools == NULL) {
317
		p = reallocarray(pools, np, sizeof(*pools));
318
		if (p == NULL) {
319
			error("realloc: %s", strerror(errno));
320
			return (-1);
321
		}
322
		/* commit */
323
		pools = p;
324
		num_pools = np;
325
	}
326
327
	num_disp = num_pools;
328
329
	for (i = 0; i < num_pools; i++) {
330
		p = &pools[i];
331
		np = i + 1;
332
333
		mib[3] = np;
334
		size = sizeof(pools[i].pool);
335
		if (sysctl(mib, nitems(mib), &p->pool, &size, NULL, 0) < 0) {
336
			p->name[0] = '\0';
337
			num_disp--;
338
			continue;
339
		}
340
341
		if (pool_get_name(np, p->name, sizeof(p->name)) < 0)
342
			snprintf(p->name, sizeof(p->name), "#%d#", i + 1);
343
	}
344
345
	return 0;
346
}
347
348
349
void
350
print_pool(void)
351
{
352
	struct pool_info *p;
353
	int i, n, count = 0;
354
355
	if (pools == NULL)
356
		return;
357
358
	for (n = i = 0; i < num_pools; i++) {
359
		p = &pools[i];
360
		if (p->name[0] == 0)
361
			continue;
362
363
		if (!print_all &&
364
		   (p->pool.pr_nget == 0 && p->pool.pr_npagealloc == 0))
365
			continue;
366
367
		if (n++ < dispstart)
368
			continue;
369
		showpool(i);
370
		count++;
371
		if (maxprint > 0 && count >= maxprint)
372
			break;
373
	}
374
}
375
376
int
377
initpool(void)
378
{
379
	field_view *v;
380
381
	add_view(&pool_view);
382
	read_pool();
383
384
	ncpusfound = hw_ncpusfound();
385
	if (ncpusfound == -1) {
386
		error("sysctl(ncpusfound): %s", strerror(errno));
387
		exit(1);
388
	}
389
390
	add_view(&pool_cache_view);
391
	pool_cache_read();
392
393
	return(0);
394
}
395
396
void
397
showpool(int k)
398
{
399
	struct pool_info *p = pools + k;
400
401
	if (k < 0 || k >= num_pools)
402
		return;
403
404
	print_fld_str(FLD_POOL_NAME, p->name);
405
	print_fld_uint(FLD_POOL_SIZE, p->pool.pr_size);
406
407
	print_fld_size(FLD_POOL_REQS, p->pool.pr_nget);
408
	print_fld_size(FLD_POOL_FAIL, p->pool.pr_nfail);
409
	print_fld_ssize(FLD_POOL_INUSE, p->pool.pr_nget - p->pool.pr_nput);
410
	print_fld_size(FLD_POOL_PGREQ, p->pool.pr_npagealloc);
411
	print_fld_size(FLD_POOL_PGREL, p->pool.pr_npagefree);
412
413
	print_fld_size(FLD_POOL_NPAGE, p->pool.pr_npages);
414
	print_fld_size(FLD_POOL_HIWAT, p->pool.pr_hiwat);
415
	print_fld_size(FLD_POOL_MINPG, p->pool.pr_minpages);
416
417
	if (p->pool.pr_maxpages == UINT_MAX)
418
		print_fld_str(FLD_POOL_MAXPG, "inf");
419
	else
420
		print_fld_size(FLD_POOL_MAXPG, p->pool.pr_maxpages);
421
422
	print_fld_size(FLD_POOL_IDLE, p->pool.pr_nidle);
423
424
	end_line();
425
}
426
427
int
428
pool_keyboard_callback(int ch)
429
{
430
	switch (ch) {
431
	case 'A':
432
		print_all ^= 1;
433
		gotsig_alarm = 1;
434
	default:
435
		return keyboard_callback(ch);
436
	};
437
438
	return (1);
439
}
440
441
int
442
pool_cache_read(void)
443
{
444
	struct pool_cache_info *pc;
445
	int np, i;
446
447
	np = pool_get_npools();
448
	if (np == -1) {
449
		error("sysctl(npools): %s", strerror(errno));
450
		return (-1);
451
	}
452
453
	if (np > num_pool_caches) {
454
		pc = reallocarray(pool_caches, np, sizeof(*pc));
455
		if (pc == NULL) {
456
			error("realloc: %s", strerror(errno));
457
			return (-1);
458
		}
459
		/* commit to using the new memory */
460
		pool_caches = pc;
461
462
		for (i = num_pool_caches; i < np; i++) {
463
			pc = &pool_caches[i];
464
			pc->name[0] = '\0';
465
466
			pc->cache_cpus = reallocarray(NULL, ncpusfound,
467
			    sizeof(*pc->cache_cpus));
468
			if (pc->cache_cpus == NULL) {
469
				error("malloc cache cpus: %s", strerror(errno));
470
				goto unalloc;
471
			}
472
		}
473
474
		/* commit to using the new cache_infos */
475
		num_pool_caches = np;
476
	}
477
478
	for (i = 0; i < num_pool_caches; i++) {
479
		pc = &pool_caches[i];
480
		np = i + 1;
481
482
		if (pool_get_cache(np, &pc->cache) < 0 ||
483
		    pool_get_cache_cpus(np, pc->cache_cpus, ncpusfound) < 0) {
484
			pc->name[0] = '\0';
485
			continue;
486
		}
487
488
		if (pool_get_name(np, pc->name, sizeof(pc->name)) < 0)
489
			snprintf(pc->name, sizeof(pc->name), "#%d#", i + 1);
490
	}
491
492
	return 0;
493
494
unalloc:
495
	while (i > num_pool_caches) {
496
		pc = &pool_caches[--i];
497
		free(pc->cache_cpus);
498
	}
499
	return (-1);
500
}
501
502
void
503
pool_cache_sort(void)
504
{
505
	/* XXX */
506
	order_type *ordering;
507
508
	if (curr_mgr == NULL)
509
		return;
510
511
	ordering = curr_mgr->order_curr;
512
513
	if (ordering == NULL)
514
		return;
515
	if (ordering->func == NULL)
516
		return;
517
	if (pools == NULL)
518
		return;
519
	if (num_pools <= 0)
520
		return;
521
522
	mergesort(pools, num_pools, sizeof(struct pool_info), ordering->func);
523
}
524
525
void
526
pool_cache_print(void)
527
{
528
	struct pool_cache_info *pc;
529
	int i, n, count = 0;
530
531
	if (pool_caches == NULL)
532
		return;
533
534
	for (n = i = 0; i < num_pool_caches; i++) {
535
		pc = &pool_caches[i];
536
		if (pc->name[0] == '\0')
537
			continue;
538
539
		if (n++ < dispstart)
540
			continue;
541
542
		pool_cache_show(pc);
543
		count++;
544
		if (maxprint > 0 && count >= maxprint)
545
			break;
546
	}
547
}
548
549
void
550
pool_cache_show(const struct pool_cache_info *pc)
551
{
552
	const struct kinfo_pool_cache *kpc;
553
	const struct kinfo_pool_cache_cpu *kpcc;
554
	int cpu;
555
556
	kpc = &pc->cache;
557
558
	print_fld_str(FLD_POOL_CACHE_NAME, pc->name);
559
	print_fld_uint(FLD_POOL_CACHE_LEN, kpc->pr_len);
560
	print_fld_uint(FLD_POOL_CACHE_IDLE, kpc->pr_nitems);
561
	print_fld_size(FLD_POOL_CACHE_NGC, kpc->pr_ngc);
562
563
	for (cpu = 0; cpu < ncpusfound; cpu++) {
564
		kpcc = &pc->cache_cpus[cpu];
565
566
		print_fld_uint(FLD_POOL_CACHE_CPU, kpcc->pr_cpu);
567
568
		print_fld_size(FLD_POOL_CACHE_GET, kpcc->pr_nget);
569
		print_fld_size(FLD_POOL_CACHE_PUT, kpcc->pr_nput);
570
		print_fld_size(FLD_POOL_CACHE_LGET, kpcc->pr_nlget);
571
		print_fld_size(FLD_POOL_CACHE_LPUT, kpcc->pr_nlput);
572
		end_line();
573
	}
574
575
}
576
577
static int
578
pool_get_npools(void)
579
{
580
	int mib[] = { CTL_KERN, KERN_POOL, KERN_POOL_NPOOLS };
581
582
	return (sysctl_rdint(mib, nitems(mib)));
583
}
584
585
static int
586
pool_get_cache(int pool, struct kinfo_pool_cache *kpc)
587
{
588
	int mib[] = { CTL_KERN, KERN_POOL, KERN_POOL_CACHE, pool };
589
	size_t len = sizeof(*kpc);
590
591
	return (sysctl(mib, nitems(mib), kpc, &len, NULL, 0));
592
}
593
594
static int
595
pool_get_cache_cpus(int pool, struct kinfo_pool_cache_cpu *kpcc,
596
    unsigned int ncpus)
597
{
598
	int mib[] = { CTL_KERN, KERN_POOL, KERN_POOL_CACHE_CPUS, pool };
599
	size_t len = sizeof(*kpcc) * ncpus;
600
601
	return (sysctl(mib, nitems(mib), kpcc, &len, NULL, 0));
602
}
603
604
static int
605
pool_get_name(int pool, char *name, size_t len)
606
{
607
	int mib[] = { CTL_KERN, KERN_POOL, KERN_POOL_NAME, pool };
608
609
	return (sysctl(mib, nitems(mib), name, &len, NULL, 0));
610
}
611
612
static int
613
hw_ncpusfound(void)
614
{
615
	int mib[] = { CTL_HW, HW_NCPUFOUND };
616
617
	return (sysctl_rdint(mib, nitems(mib)));
618
}
619
620
static int
621
sysctl_rdint(const int *mib, unsigned int nmib)
622
{
623
	int i;
624
	size_t size = sizeof(i);
625
626
	if (sysctl(mib, nmib, &i, &size, NULL, 0) == -1)
627
		return (-1);
628
629
	return (i);
630
}