xref: /openbsd/usr.bin/systat/uvm.c (revision 5dea098c)
1 /*	$OpenBSD: uvm.c,v 1.9 2024/05/01 12:54:27 mpi 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 
36 void print_uvm(void);
37 int  read_uvm(void);
38 int  select_uvm(void);
39 
40 void print_uvmexp_field(field_def *, field_def *, int *, int *, const char *);
41 void print_uvmexp_line(int);
42 
43 struct uvmexp uvmexp;
44 struct uvmexp last_uvmexp;
45 
46 struct uvmline {
47 	int	*v1;
48 	int	*ov1;
49 	char	*n1;
50 	int	*v2;
51 	int	*ov2;
52 	char	*n2;
53 	int	*v3;
54 	int	*ov3;
55 	char	*n3;
56 };
57 
58 struct uvmline uvmline[] = {
59 	{ NULL, NULL, "Page Counters",
60 	  NULL, NULL, "Stats Counters",
61 	  NULL, NULL, "Fault Counters" },
62 	{ &uvmexp.npages, &last_uvmexp.npages, "npages",
63 	  &uvmexp.faults, &last_uvmexp.faults, "faults",
64 	  &uvmexp.fltnoram, &last_uvmexp.fltnoram, "fltnoram" },
65 	{ &uvmexp.free, &last_uvmexp.free, "free",
66 	  &uvmexp.traps, &last_uvmexp.traps, "traps",
67 	  &uvmexp.fltnoanon, &last_uvmexp.fltnoanon, "fltnoanon" },
68 	{ &uvmexp.active, &last_uvmexp.active, "active",
69 	  &uvmexp.intrs, &last_uvmexp.intrs, "intrs",
70 	  &uvmexp.fltnoamap, &last_uvmexp.fltnoamap, "fltnoamap" },
71 	{ &uvmexp.inactive, &last_uvmexp.inactive, "inactive",
72 	  &uvmexp.swtch, &last_uvmexp.swtch, "swtch",
73 	  &uvmexp.fltpgwait, &last_uvmexp.fltpgwait, "fltpgwait" },
74 	{ &uvmexp.paging, &last_uvmexp.paging, "paging",
75 	  &uvmexp.softs, &last_uvmexp.softs, "softs",
76 	  &uvmexp.fltpgrele, &last_uvmexp.fltpgrele, "fltpgrele" },
77 	{ &uvmexp.wired, &last_uvmexp.wired, "wired",
78 	  &uvmexp.syscalls, &last_uvmexp.syscalls, "syscalls",
79 	  &uvmexp.fltrelck, &last_uvmexp.fltrelck, "fltrelck" },
80 	{ &uvmexp.zeropages, &last_uvmexp.zeropages, "zeropages",
81 	  &uvmexp.pageins, &last_uvmexp.pageins, "pageins",
82 	  &uvmexp.fltrelckok, &last_uvmexp.fltrelckok, "fltrelckok" },
83 	{ &uvmexp.percpucaches, &last_uvmexp.percpucaches, "percpucaches",
84 	  &uvmexp.pgswapin, &last_uvmexp.pgswapin, "pgswapin",
85 	  &uvmexp.fltanget, &last_uvmexp.fltanget, "fltanget" },
86 	{ NULL, NULL, NULL,
87 	  &uvmexp.pgswapout, &last_uvmexp.pgswapout, "pgswapout",
88 	  &uvmexp.fltanretry, &last_uvmexp.fltanretry, "fltanretry" },
89 	{ NULL, NULL, NULL,
90 	  &uvmexp.forks, &last_uvmexp.forks, "forks",
91 	  &uvmexp.fltamcopy, &last_uvmexp.fltamcopy, "fltamcopy" },
92 	{ NULL, NULL, "Pageout Params",
93 	  &uvmexp.forks_ppwait, &last_uvmexp.forks_ppwait, "forks_ppwait",
94 	  &uvmexp.fltnamap, &last_uvmexp.fltnamap, "fltnamap" },
95 	{ &uvmexp.freemin, &last_uvmexp.freemin, "freemin",
96 	  &uvmexp.forks_sharevm, &last_uvmexp.forks_sharevm, "forks_sharevm",
97 	  &uvmexp.fltnomap, &last_uvmexp.fltnomap, "fltnomap" },
98 	{ &uvmexp.freetarg, &last_uvmexp.freetarg, "freetarg",
99 	  &uvmexp.pga_zerohit, &last_uvmexp.pga_zerohit, "pga_zerohit",
100 	  &uvmexp.fltlget, &last_uvmexp.fltlget, "fltlget" },
101 	{ &uvmexp.inactarg, &last_uvmexp.inactarg, "inactarg",
102 	  &uvmexp.pga_zeromiss, &last_uvmexp.pga_zeromiss, "pga_zeromiss",
103 	  &uvmexp.fltget, &last_uvmexp.fltget, "fltget" },
104 	{ &uvmexp.wiredmax, &last_uvmexp.wiredmax, "wiredmax",
105 	  NULL, NULL, NULL,
106 	  &uvmexp.flt_anon, &last_uvmexp.flt_anon, "flt_anon" },
107 	{ &uvmexp.anonmin, &last_uvmexp.anonmin, "anonmin",
108 	  NULL, NULL, "Daemon Counters",
109 	  &uvmexp.flt_acow, &last_uvmexp.flt_acow, "flt_acow" },
110 	{ &uvmexp.vtextmin, &last_uvmexp.vtextmin, "vtextmin",
111 	  &uvmexp.pdwoke, &last_uvmexp.pdwoke, "pdwoke",
112 	  &uvmexp.flt_obj, &last_uvmexp.flt_obj, "flt_obj" },
113 	{ &uvmexp.vnodemin, &last_uvmexp.vnodemin, "vnodemin",
114 	  &uvmexp.pdrevs, &last_uvmexp.pdrevs, "pdrevs",
115 	  &uvmexp.flt_prcopy, &last_uvmexp.flt_prcopy, "flt_prcopy" },
116 	{ &uvmexp.anonminpct, &last_uvmexp.anonminpct, "anonminpct",
117 	  &uvmexp.pdswout, &last_uvmexp.pdswout, "pdswout",
118 	  &uvmexp.flt_przero, &last_uvmexp.flt_przero, "flt_przero" },
119 	{ &uvmexp.vtextminpct, &last_uvmexp.vtextminpct, "vtextminpct",
120 	  &uvmexp.swpgonly, &last_uvmexp.swpgonly, "swpgonly",
121 	  NULL, NULL, NULL },
122 	{ &uvmexp.vnodeminpct, &last_uvmexp.vnodeminpct, "vnodeminpct",
123 	  &uvmexp.pdfreed, &last_uvmexp.pdfreed, "pdfreed",
124 	  NULL, NULL, "Swap Counters" },
125 	{ NULL, NULL, NULL,
126 	  &uvmexp.pdscans, &last_uvmexp.pdscans, "pdscans",
127 	  &uvmexp.nswapdev, &last_uvmexp.nswapdev, "nswapdev" },
128 	{ NULL, NULL, "Misc Counters",
129 	  &uvmexp.pdanscan, &last_uvmexp.pdanscan, "pdanscan",
130 	  &uvmexp.swpages, &last_uvmexp.swpages, "swpages" },
131 	{ &uvmexp.fpswtch, &last_uvmexp.fpswtch, "fpswtch",
132 	  &uvmexp.pdobscan, &last_uvmexp.pdobscan, "pdobscan",
133 	  &uvmexp.swpginuse, &last_uvmexp.swpginuse, "swpginuse" },
134 	{ &uvmexp.kmapent, &last_uvmexp.kmapent, "kmapent",
135 	  &uvmexp.pdreact, &last_uvmexp.pdreact, "pdreact",
136 	  &uvmexp.swpgonly, &last_uvmexp.swpgonly, "swpgonly" },
137 	{ NULL, NULL, NULL,
138 	  &uvmexp.pdbusy, &last_uvmexp.pdbusy, "pdbusy",
139 	  &uvmexp.nswget, &last_uvmexp.nswget, "nswget" },
140 	{ NULL, NULL, "Constants",
141 	  &uvmexp.pdpageouts, &last_uvmexp.pdpageouts, "pdpageouts",
142 	  NULL, NULL, NULL },
143 	{ &uvmexp.pagesize, &last_uvmexp.pagesize, "pagesize",
144 	  &uvmexp.pdpending, &last_uvmexp.pdpending, "pdpending",
145 	  NULL, NULL, "Per-CPU Counters" },
146 	{ &uvmexp.pagemask, &last_uvmexp.pagemask, "pagemask",
147 	  &uvmexp.pddeact, &last_uvmexp.pddeact, "pddeact",
148 	  &uvmexp.pcphit, &last_uvmexp.pcphit, "pcphit" },
149 	{ &uvmexp.pageshift, &last_uvmexp.pageshift, "pageshift",
150 	  NULL, NULL, NULL,
151 	  &uvmexp.pcpmiss, &last_uvmexp.pcpmiss, "pcpmiss" }
152 };
153 
154 field_def fields_uvm[] = {
155 	{"",	 5,10,1, FLD_ALIGN_RIGHT,	-1,0,0,0 },
156 	{"",	18,19,1, FLD_ALIGN_LEFT,	-1,0,0,0 },
157 	{"",	 5,10,1, FLD_ALIGN_RIGHT,	-1,0,0,0 },
158 	{"",	18,19,1, FLD_ALIGN_LEFT,	-1,0,0,0 },
159 	{"",	 5,10,1, FLD_ALIGN_RIGHT,	-1,0,0,0 },
160 	{"",	18,19,1, FLD_ALIGN_LEFT,	-1,0,0,0 },
161 };
162 
163 #define	FLD_VALUE1		FIELD_ADDR(fields_uvm,  0)
164 #define	FLD_NAME1		FIELD_ADDR(fields_uvm,  1)
165 #define	FLD_VALUE2		FIELD_ADDR(fields_uvm,  2)
166 #define	FLD_NAME2		FIELD_ADDR(fields_uvm,  3)
167 #define	FLD_VALUE3		FIELD_ADDR(fields_uvm,  4)
168 #define	FLD_NAME3		FIELD_ADDR(fields_uvm,  5)
169 
170 /* Define views */
171 field_def *view_uvm_0[] = {
172 	FLD_VALUE1, FLD_NAME1,
173 	FLD_VALUE2, FLD_NAME2,
174 	FLD_VALUE3, FLD_NAME3,
175 	NULL
176 };
177 
178 /* Define view managers */
179 struct view_manager uvm_mgr = {
180 	"UVM", select_uvm, read_uvm, NULL, print_header,
181 	print_uvm, keyboard_callback, NULL, NULL
182 };
183 
184 field_view uvm_view = {
185 	view_uvm_0,
186 	"uvm",
187 	'5',
188 	&uvm_mgr
189 };
190 
191 int
192 select_uvm(void)
193 {
194 	return (0);
195 }
196 
197 int
198 read_uvm(void)
199 {
200 	static int uvmexp_mib[2] = { CTL_VM, VM_UVMEXP };
201 	size_t size;
202 
203 	num_disp = nitems(uvmline);
204 	memcpy(&last_uvmexp, &uvmexp, sizeof(uvmexp));
205 
206 	size = sizeof(uvmexp);
207 	if (sysctl(uvmexp_mib, 2, &uvmexp, &size, NULL, 0) == -1) {
208 		error("Can't get VM_UVMEXP: %s\n", strerror(errno));
209 		memset(&uvmexp, 0, sizeof(uvmexp));
210 	}
211 
212 	return 0;
213 }
214 
215 void
216 print_uvmexp_field(field_def *fvalue, field_def *fname, int *new, int *old,
217     const char *name)
218 {
219 	char *uppername;
220 	size_t len, i;
221 
222 	if (new == NULL && name == NULL)
223 		return;
224 
225 	if (new == NULL) {
226 		print_fld_str(fvalue, "=====");
227 		print_fld_str(fname, name);
228 		return;
229 	}
230 
231 	if (*new != 0)
232 		print_fld_ssize(fvalue, *new);
233 	if (*new == *old) {
234 		print_fld_str(fname, name);
235 		return;
236 	}
237 	len = strlen(name);
238 	uppername = malloc(len + 1);
239 	if (uppername == NULL)
240 		err(1, "malloc");
241 	for (i = 0; i < len; i++)
242 		uppername[i] = toupper(name[i]);
243 	uppername[len] = '\0';
244 	print_fld_str(fname, uppername);
245 	free(uppername);
246 }
247 
248 void
249 print_uvm(void)
250 {
251 	struct uvmline *l;
252 	int i, maxline;
253 
254 	maxline = nitems(uvmline);
255 	if (maxline > (dispstart + maxprint))
256 		maxline = dispstart + maxprint;
257 
258 	for (i = dispstart; i < nitems(uvmline); i++) {
259 		l = &uvmline[i];
260 		print_uvmexp_field(FLD_VALUE1, FLD_NAME1, l->v1, l->ov1, l->n1);
261 		print_uvmexp_field(FLD_VALUE2, FLD_NAME2, l->v2, l->ov2, l->n2);
262 		print_uvmexp_field(FLD_VALUE3, FLD_NAME3, l->v3, l->ov3, l->n3);
263 		end_line();
264 	}
265 }
266 
267 int
268 inituvm(void)
269 {
270 	add_view(&uvm_view);
271 	read_uvm();
272 
273 	return(0);
274 }
275