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
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
42 struct uvmexp uvmexp;
43 struct uvmexp last_uvmexp;
44
45 struct 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
57 struct 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
153 field_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 */
170 field_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 */
178 struct view_manager uvm_mgr = {
179 "UVM", select_uvm, read_uvm, NULL, print_header,
180 print_uvm, keyboard_callback, NULL, NULL
181 };
182
183 field_view uvm_view = {
184 view_uvm_0,
185 "uvm",
186 '5',
187 &uvm_mgr
188 };
189
190 int
select_uvm(void)191 select_uvm(void)
192 {
193 return (0);
194 }
195
196 int
read_uvm(void)197 read_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
214 void
print_uvmexp_field(field_def * fvalue,field_def * fname,int * new,int * old,const char * name)215 print_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
247 void
print_uvm(void)248 print_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
266 int
inituvm(void)267 inituvm(void)
268 {
269 add_view(&uvm_view);
270 read_uvm();
271
272 return(0);
273 }
274