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