1/*	$OpenBSD: uvm.c,v 1.10 2024/05/18 09:02:34 jsg Exp $	*/
2/*
3 * Copyright (c) 2008 Can Erkin Acar <canacar@openbsd.org>
4 * Copyright (c) 2018 Kenneth R Westerback <krw@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <sys/types.h>
20#include <sys/signal.h>
21#include <sys/sysctl.h>
22#include <sys/pool.h>
23#include <ctype.h>
24#include <err.h>
25#include <errno.h>
26#include <stdlib.h>
27#include <string.h>
28#include <limits.h>
29
30#include "systat.h"
31
32#ifndef nitems
33#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
34#endif
35
36void print_uvm(void);
37int  read_uvm(void);
38int  select_uvm(void);
39
40void print_uvmexp_field(field_def *, field_def *, int *, int *, const char *);
41
42struct uvmexp uvmexp;
43struct uvmexp last_uvmexp;
44
45struct uvmline {
46	int	*v1;
47	int	*ov1;
48	char	*n1;
49	int	*v2;
50	int	*ov2;
51	char	*n2;
52	int	*v3;
53	int	*ov3;
54	char	*n3;
55};
56
57struct uvmline uvmline[] = {
58	{ NULL, NULL, "Page Counters",
59	  NULL, NULL, "Stats Counters",
60	  NULL, NULL, "Fault Counters" },
61	{ &uvmexp.npages, &last_uvmexp.npages, "npages",
62	  &uvmexp.faults, &last_uvmexp.faults, "faults",
63	  &uvmexp.fltnoram, &last_uvmexp.fltnoram, "fltnoram" },
64	{ &uvmexp.free, &last_uvmexp.free, "free",
65	  &uvmexp.traps, &last_uvmexp.traps, "traps",
66	  &uvmexp.fltnoanon, &last_uvmexp.fltnoanon, "fltnoanon" },
67	{ &uvmexp.active, &last_uvmexp.active, "active",
68	  &uvmexp.intrs, &last_uvmexp.intrs, "intrs",
69	  &uvmexp.fltnoamap, &last_uvmexp.fltnoamap, "fltnoamap" },
70	{ &uvmexp.inactive, &last_uvmexp.inactive, "inactive",
71	  &uvmexp.swtch, &last_uvmexp.swtch, "swtch",
72	  &uvmexp.fltpgwait, &last_uvmexp.fltpgwait, "fltpgwait" },
73	{ &uvmexp.paging, &last_uvmexp.paging, "paging",
74	  &uvmexp.softs, &last_uvmexp.softs, "softs",
75	  &uvmexp.fltpgrele, &last_uvmexp.fltpgrele, "fltpgrele" },
76	{ &uvmexp.wired, &last_uvmexp.wired, "wired",
77	  &uvmexp.syscalls, &last_uvmexp.syscalls, "syscalls",
78	  &uvmexp.fltrelck, &last_uvmexp.fltrelck, "fltrelck" },
79	{ &uvmexp.zeropages, &last_uvmexp.zeropages, "zeropages",
80	  &uvmexp.pageins, &last_uvmexp.pageins, "pageins",
81	  &uvmexp.fltrelckok, &last_uvmexp.fltrelckok, "fltrelckok" },
82	{ &uvmexp.percpucaches, &last_uvmexp.percpucaches, "percpucaches",
83	  &uvmexp.pgswapin, &last_uvmexp.pgswapin, "pgswapin",
84	  &uvmexp.fltanget, &last_uvmexp.fltanget, "fltanget" },
85	{ NULL, NULL, NULL,
86	  &uvmexp.pgswapout, &last_uvmexp.pgswapout, "pgswapout",
87	  &uvmexp.fltanretry, &last_uvmexp.fltanretry, "fltanretry" },
88	{ NULL, NULL, NULL,
89	  &uvmexp.forks, &last_uvmexp.forks, "forks",
90	  &uvmexp.fltamcopy, &last_uvmexp.fltamcopy, "fltamcopy" },
91	{ NULL, NULL, "Pageout Params",
92	  &uvmexp.forks_ppwait, &last_uvmexp.forks_ppwait, "forks_ppwait",
93	  &uvmexp.fltnamap, &last_uvmexp.fltnamap, "fltnamap" },
94	{ &uvmexp.freemin, &last_uvmexp.freemin, "freemin",
95	  &uvmexp.forks_sharevm, &last_uvmexp.forks_sharevm, "forks_sharevm",
96	  &uvmexp.fltnomap, &last_uvmexp.fltnomap, "fltnomap" },
97	{ &uvmexp.freetarg, &last_uvmexp.freetarg, "freetarg",
98	  &uvmexp.pga_zerohit, &last_uvmexp.pga_zerohit, "pga_zerohit",
99	  &uvmexp.fltlget, &last_uvmexp.fltlget, "fltlget" },
100	{ &uvmexp.inactarg, &last_uvmexp.inactarg, "inactarg",
101	  &uvmexp.pga_zeromiss, &last_uvmexp.pga_zeromiss, "pga_zeromiss",
102	  &uvmexp.fltget, &last_uvmexp.fltget, "fltget" },
103	{ &uvmexp.wiredmax, &last_uvmexp.wiredmax, "wiredmax",
104	  NULL, NULL, NULL,
105	  &uvmexp.flt_anon, &last_uvmexp.flt_anon, "flt_anon" },
106	{ &uvmexp.anonmin, &last_uvmexp.anonmin, "anonmin",
107	  NULL, NULL, "Daemon Counters",
108	  &uvmexp.flt_acow, &last_uvmexp.flt_acow, "flt_acow" },
109	{ &uvmexp.vtextmin, &last_uvmexp.vtextmin, "vtextmin",
110	  &uvmexp.pdwoke, &last_uvmexp.pdwoke, "pdwoke",
111	  &uvmexp.flt_obj, &last_uvmexp.flt_obj, "flt_obj" },
112	{ &uvmexp.vnodemin, &last_uvmexp.vnodemin, "vnodemin",
113	  &uvmexp.pdrevs, &last_uvmexp.pdrevs, "pdrevs",
114	  &uvmexp.flt_prcopy, &last_uvmexp.flt_prcopy, "flt_prcopy" },
115	{ &uvmexp.anonminpct, &last_uvmexp.anonminpct, "anonminpct",
116	  &uvmexp.pdswout, &last_uvmexp.pdswout, "pdswout",
117	  &uvmexp.flt_przero, &last_uvmexp.flt_przero, "flt_przero" },
118	{ &uvmexp.vtextminpct, &last_uvmexp.vtextminpct, "vtextminpct",
119	  &uvmexp.swpgonly, &last_uvmexp.swpgonly, "swpgonly",
120	  NULL, NULL, NULL },
121	{ &uvmexp.vnodeminpct, &last_uvmexp.vnodeminpct, "vnodeminpct",
122	  &uvmexp.pdfreed, &last_uvmexp.pdfreed, "pdfreed",
123	  NULL, NULL, "Swap Counters" },
124	{ NULL, NULL, NULL,
125	  &uvmexp.pdscans, &last_uvmexp.pdscans, "pdscans",
126	  &uvmexp.nswapdev, &last_uvmexp.nswapdev, "nswapdev" },
127	{ NULL, NULL, "Misc Counters",
128	  &uvmexp.pdanscan, &last_uvmexp.pdanscan, "pdanscan",
129	  &uvmexp.swpages, &last_uvmexp.swpages, "swpages" },
130	{ &uvmexp.fpswtch, &last_uvmexp.fpswtch, "fpswtch",
131	  &uvmexp.pdobscan, &last_uvmexp.pdobscan, "pdobscan",
132	  &uvmexp.swpginuse, &last_uvmexp.swpginuse, "swpginuse" },
133	{ &uvmexp.kmapent, &last_uvmexp.kmapent, "kmapent",
134	  &uvmexp.pdreact, &last_uvmexp.pdreact, "pdreact",
135	  &uvmexp.swpgonly, &last_uvmexp.swpgonly, "swpgonly" },
136	{ NULL, NULL, NULL,
137	  &uvmexp.pdbusy, &last_uvmexp.pdbusy, "pdbusy",
138	  &uvmexp.nswget, &last_uvmexp.nswget, "nswget" },
139	{ NULL, NULL, "Constants",
140	  &uvmexp.pdpageouts, &last_uvmexp.pdpageouts, "pdpageouts",
141	  NULL, NULL, NULL },
142	{ &uvmexp.pagesize, &last_uvmexp.pagesize, "pagesize",
143	  &uvmexp.pdpending, &last_uvmexp.pdpending, "pdpending",
144	  NULL, NULL, "Per-CPU Counters" },
145	{ &uvmexp.pagemask, &last_uvmexp.pagemask, "pagemask",
146	  &uvmexp.pddeact, &last_uvmexp.pddeact, "pddeact",
147	  &uvmexp.pcphit, &last_uvmexp.pcphit, "pcphit" },
148	{ &uvmexp.pageshift, &last_uvmexp.pageshift, "pageshift",
149	  NULL, NULL, NULL,
150	  &uvmexp.pcpmiss, &last_uvmexp.pcpmiss, "pcpmiss" }
151};
152
153field_def fields_uvm[] = {
154	{"",	 5,10,1, FLD_ALIGN_RIGHT,	-1,0,0,0 },
155	{"",	18,19,1, FLD_ALIGN_LEFT,	-1,0,0,0 },
156	{"",	 5,10,1, FLD_ALIGN_RIGHT,	-1,0,0,0 },
157	{"",	18,19,1, FLD_ALIGN_LEFT,	-1,0,0,0 },
158	{"",	 5,10,1, FLD_ALIGN_RIGHT,	-1,0,0,0 },
159	{"",	18,19,1, FLD_ALIGN_LEFT,	-1,0,0,0 },
160};
161
162#define	FLD_VALUE1		FIELD_ADDR(fields_uvm,  0)
163#define	FLD_NAME1		FIELD_ADDR(fields_uvm,  1)
164#define	FLD_VALUE2		FIELD_ADDR(fields_uvm,  2)
165#define	FLD_NAME2		FIELD_ADDR(fields_uvm,  3)
166#define	FLD_VALUE3		FIELD_ADDR(fields_uvm,  4)
167#define	FLD_NAME3		FIELD_ADDR(fields_uvm,  5)
168
169/* Define views */
170field_def *view_uvm_0[] = {
171	FLD_VALUE1, FLD_NAME1,
172	FLD_VALUE2, FLD_NAME2,
173	FLD_VALUE3, FLD_NAME3,
174	NULL
175};
176
177/* Define view managers */
178struct view_manager uvm_mgr = {
179	"UVM", select_uvm, read_uvm, NULL, print_header,
180	print_uvm, keyboard_callback, NULL, NULL
181};
182
183field_view uvm_view = {
184	view_uvm_0,
185	"uvm",
186	'5',
187	&uvm_mgr
188};
189
190int
191select_uvm(void)
192{
193	return (0);
194}
195
196int
197read_uvm(void)
198{
199	static int uvmexp_mib[2] = { CTL_VM, VM_UVMEXP };
200	size_t size;
201
202	num_disp = nitems(uvmline);
203	memcpy(&last_uvmexp, &uvmexp, sizeof(uvmexp));
204
205	size = sizeof(uvmexp);
206	if (sysctl(uvmexp_mib, 2, &uvmexp, &size, NULL, 0) == -1) {
207		error("Can't get VM_UVMEXP: %s\n", strerror(errno));
208		memset(&uvmexp, 0, sizeof(uvmexp));
209	}
210
211	return 0;
212}
213
214void
215print_uvmexp_field(field_def *fvalue, field_def *fname, int *new, int *old,
216    const char *name)
217{
218	char *uppername;
219	size_t len, i;
220
221	if (new == NULL && name == NULL)
222		return;
223
224	if (new == NULL) {
225		print_fld_str(fvalue, "=====");
226		print_fld_str(fname, name);
227		return;
228	}
229
230	if (*new != 0)
231		print_fld_ssize(fvalue, *new);
232	if (*new == *old) {
233		print_fld_str(fname, name);
234		return;
235	}
236	len = strlen(name);
237	uppername = malloc(len + 1);
238	if (uppername == NULL)
239		err(1, "malloc");
240	for (i = 0; i < len; i++)
241		uppername[i] = toupper(name[i]);
242	uppername[len] = '\0';
243	print_fld_str(fname, uppername);
244	free(uppername);
245}
246
247void
248print_uvm(void)
249{
250	struct uvmline *l;
251	int i, maxline;
252
253	maxline = nitems(uvmline);
254	if (maxline > (dispstart + maxprint))
255		maxline = dispstart + maxprint;
256
257	for (i = dispstart; i < nitems(uvmline); i++) {
258		l = &uvmline[i];
259		print_uvmexp_field(FLD_VALUE1, FLD_NAME1, l->v1, l->ov1, l->n1);
260		print_uvmexp_field(FLD_VALUE2, FLD_NAME2, l->v2, l->ov2, l->n2);
261		print_uvmexp_field(FLD_VALUE3, FLD_NAME3, l->v3, l->ov3, l->n3);
262		end_line();
263	}
264}
265
266int
267inituvm(void)
268{
269	add_view(&uvm_view);
270	read_uvm();
271
272	return(0);
273}
274