1/* $OpenBSD: uvm_meter.c,v 1.50 2023/09/16 09:33:27 mpi Exp $ */ 2/* $NetBSD: uvm_meter.c,v 1.21 2001/07/14 06:36:03 matt Exp $ */ 3 4/* 5 * Copyright (c) 1997 Charles D. Cranor and Washington University. 6 * Copyright (c) 1982, 1986, 1989, 1993 7 * The Regents of the University of California. 8 * 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * @(#)vm_meter.c 8.4 (Berkeley) 1/4/94 36 * from: Id: uvm_meter.c,v 1.1.2.1 1997/08/14 19:10:35 chuck Exp 37 */ 38 39#include <sys/param.h> 40#include <sys/systm.h> 41#include <sys/kernel.h> 42#include <sys/percpu.h> 43#include <sys/proc.h> 44#include <sys/sysctl.h> 45#include <sys/vmmeter.h> 46#include <uvm/uvm.h> 47#include <uvm/uvm_ddb.h> 48 49#ifdef UVM_SWAP_ENCRYPT 50#include <uvm/uvm_swap.h> 51#include <uvm/uvm_swap_encrypt.h> 52#endif 53 54/* 55 * The time for a process to be blocked before being very swappable. 56 * This is a number of seconds which the system takes as being a non-trivial 57 * amount of real time. You probably shouldn't change this; 58 * it is used in subtle ways (fractions and multiples of it are, that is, like 59 * half of a ``long time'', almost a long time, etc.) 60 * It is related to human patience and other factors which don't really 61 * change over time. 62 */ 63#define MAXSLP 20 64 65int maxslp = MAXSLP; /* patchable ... */ 66 67extern struct loadavg averunnable; 68 69void uvm_total(struct vmtotal *); 70void uvmexp_read(struct uvmexp *); 71 72char malloc_conf[16]; 73 74/* 75 * uvm_sysctl: sysctl hook into UVM system. 76 */ 77int 78uvm_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, 79 size_t newlen, struct proc *p) 80{ 81 struct process *pr = p->p_p; 82 struct vmtotal vmtotals; 83 struct uvmexp uexp; 84 int rv, t; 85 86 switch (name[0]) { 87 case VM_SWAPENCRYPT: 88#ifdef UVM_SWAP_ENCRYPT 89 return (swap_encrypt_ctl(name + 1, namelen - 1, oldp, oldlenp, 90 newp, newlen, p)); 91#else 92 return (EOPNOTSUPP); 93#endif 94 default: 95 /* all sysctl names at this level are terminal */ 96 if (namelen != 1) 97 return (ENOTDIR); /* overloaded */ 98 break; 99 } 100 101 switch (name[0]) { 102 case VM_LOADAVG: 103 return (sysctl_rdstruct(oldp, oldlenp, newp, &averunnable, 104 sizeof(averunnable))); 105 106 case VM_METER: 107 uvm_total(&vmtotals); 108 return (sysctl_rdstruct(oldp, oldlenp, newp, &vmtotals, 109 sizeof(vmtotals))); 110 111 case VM_UVMEXP: 112 uvmexp_read(&uexp); 113 return (sysctl_rdstruct(oldp, oldlenp, newp, &uexp, 114 sizeof(uexp))); 115 116 case VM_NKMEMPAGES: 117 return (sysctl_rdint(oldp, oldlenp, newp, nkmempages)); 118 119 case VM_PSSTRINGS: 120 return (sysctl_rdstruct(oldp, oldlenp, newp, &pr->ps_strings, 121 sizeof(pr->ps_strings))); 122 123 case VM_ANONMIN: 124 t = uvmexp.anonminpct; 125 rv = sysctl_int(oldp, oldlenp, newp, newlen, &t); 126 if (rv) { 127 return rv; 128 } 129 if (t + uvmexp.vtextminpct + uvmexp.vnodeminpct > 95 || t < 0) { 130 return EINVAL; 131 } 132 uvmexp.anonminpct = t; 133 uvmexp.anonmin = t * 256 / 100; 134 return rv; 135 136 case VM_VTEXTMIN: 137 t = uvmexp.vtextminpct; 138 rv = sysctl_int(oldp, oldlenp, newp, newlen, &t); 139 if (rv) { 140 return rv; 141 } 142 if (uvmexp.anonminpct + t + uvmexp.vnodeminpct > 95 || t < 0) { 143 return EINVAL; 144 } 145 uvmexp.vtextminpct = t; 146 uvmexp.vtextmin = t * 256 / 100; 147 return rv; 148 149 case VM_VNODEMIN: 150 t = uvmexp.vnodeminpct; 151 rv = sysctl_int(oldp, oldlenp, newp, newlen, &t); 152 if (rv) { 153 return rv; 154 } 155 if (uvmexp.anonminpct + uvmexp.vtextminpct + t > 95 || t < 0) { 156 return EINVAL; 157 } 158 uvmexp.vnodeminpct = t; 159 uvmexp.vnodemin = t * 256 / 100; 160 return rv; 161 162 case VM_MAXSLP: 163 return (sysctl_rdint(oldp, oldlenp, newp, maxslp)); 164 165 case VM_USPACE: 166 return (sysctl_rdint(oldp, oldlenp, newp, USPACE)); 167 168 case VM_MALLOC_CONF: 169 return (sysctl_string(oldp, oldlenp, newp, newlen, 170 malloc_conf, sizeof(malloc_conf))); 171 default: 172 return (EOPNOTSUPP); 173 } 174 /* NOTREACHED */ 175} 176 177/* 178 * uvm_total: calculate the current state of the system. 179 */ 180void 181uvm_total(struct vmtotal *totalp) 182{ 183 struct proc *p; 184#if 0 185 struct vm_map_entry * entry; 186 struct vm_map *map; 187 int paging; 188#endif 189 190 memset(totalp, 0, sizeof *totalp); 191 192 /* calculate process statistics */ 193 LIST_FOREACH(p, &allproc, p_list) { 194 switch (p->p_stat) { 195 case 0: 196 continue; 197 198 case SSLEEP: 199 case SSTOP: 200 totalp->t_sl++; 201 break; 202 case SRUN: 203 case SONPROC: 204 if (p == p->p_cpu->ci_schedstate.spc_idleproc) 205 continue; 206 /* FALLTHROUGH */ 207 case SIDL: 208 totalp->t_rq++; 209 if (p->p_stat == SIDL) 210 continue; 211 break; 212 } 213 /* 214 * note active objects 215 */ 216#if 0 217 /* 218 * XXXCDC: BOGUS! rethink this. in the mean time 219 * don't do it. 220 */ 221 paging = 0; 222 vm_map_lock(map); 223 for (map = &p->p_vmspace->vm_map, entry = map->header.next; 224 entry != &map->header; entry = entry->next) { 225 if (entry->is_a_map || entry->is_sub_map || 226 entry->object.uvm_obj == NULL) 227 continue; 228 /* XXX how to do this with uvm */ 229 } 230 vm_map_unlock(map); 231 if (paging) 232 totalp->t_pw++; 233#endif 234 } 235 /* 236 * Calculate object memory usage statistics. 237 */ 238 totalp->t_free = uvmexp.free; 239 totalp->t_vm = uvmexp.npages - uvmexp.free + uvmexp.swpginuse; 240 totalp->t_avm = uvmexp.active + uvmexp.swpginuse; /* XXX */ 241 totalp->t_rm = uvmexp.npages - uvmexp.free; 242 totalp->t_arm = uvmexp.active; 243 totalp->t_vmshr = 0; /* XXX */ 244 totalp->t_avmshr = 0; /* XXX */ 245 totalp->t_rmshr = 0; /* XXX */ 246 totalp->t_armshr = 0; /* XXX */ 247} 248 249void 250uvmexp_read(struct uvmexp *uexp) 251{ 252 uint64_t counters[exp_ncounters], scratch[exp_ncounters]; 253 254 memcpy(uexp, &uvmexp, sizeof(*uexp)); 255 256 counters_read(uvmexp_counters, counters, exp_ncounters, 257 scratch); 258 259 /* stat counters */ 260 uexp->faults = (int)counters[faults]; 261 uexp->pageins = (int)counters[pageins]; 262 263 /* fault subcounters */ 264 uexp->fltnoram = (int)counters[flt_noram]; 265 uexp->fltnoanon = (int)counters[flt_noanon]; 266 uexp->fltnoamap = (int)counters[flt_noamap]; 267 uexp->fltpgwait = (int)counters[flt_pgwait]; 268 uexp->fltpgrele = (int)counters[flt_pgrele]; 269 uexp->fltrelck = (int)counters[flt_relck]; 270 uexp->fltrelckok = (int)counters[flt_relckok]; 271 uexp->fltanget = (int)counters[flt_anget]; 272 uexp->fltanretry = (int)counters[flt_anretry]; 273 uexp->fltamcopy = (int)counters[flt_amcopy]; 274 uexp->fltnamap = (int)counters[flt_namap]; 275 uexp->fltnomap = (int)counters[flt_nomap]; 276 uexp->fltlget = (int)counters[flt_lget]; 277 uexp->fltget = (int)counters[flt_get]; 278 uexp->flt_anon = (int)counters[flt_anon]; 279 uexp->flt_acow = (int)counters[flt_acow]; 280 uexp->flt_obj = (int)counters[flt_obj]; 281 uexp->flt_prcopy = (int)counters[flt_prcopy]; 282 uexp->flt_przero = (int)counters[flt_przero]; 283} 284 285#ifdef DDB 286 287/* 288 * uvmexp_print: ddb hook to print interesting uvm counters 289 */ 290void 291uvmexp_print(int (*pr)(const char *, ...)) 292{ 293 struct uvmexp uexp; 294 295 uvmexp_read(&uexp); 296 297 (*pr)("Current UVM status:\n"); 298 (*pr)(" pagesize=%d (0x%x), pagemask=0x%x, pageshift=%d\n", 299 uexp.pagesize, uexp.pagesize, uexp.pagemask, 300 uexp.pageshift); 301 (*pr)(" %d VM pages: %d active, %d inactive, %d wired, %d free (%d zero)\n", 302 uexp.npages, uexp.active, uexp.inactive, uexp.wired, 303 uexp.free, uexp.zeropages); 304 (*pr)(" min %d%% (%d) anon, %d%% (%d) vnode, %d%% (%d) vtext\n", 305 uexp.anonminpct, uexp.anonmin, uexp.vnodeminpct, 306 uexp.vnodemin, uexp.vtextminpct, uexp.vtextmin); 307 (*pr)(" freemin=%d, free-target=%d, inactive-target=%d, " 308 "wired-max=%d\n", uexp.freemin, uexp.freetarg, uexp.inactarg, 309 uexp.wiredmax); 310 (*pr)(" faults=%d, traps=%d, intrs=%d, ctxswitch=%d fpuswitch=%d\n", 311 uexp.faults, uexp.traps, uexp.intrs, uexp.swtch, 312 uexp.fpswtch); 313 (*pr)(" softint=%d, syscalls=%d, kmapent=%d\n", 314 uexp.softs, uexp.syscalls, uexp.kmapent); 315 316 (*pr)(" fault counts:\n"); 317 (*pr)(" noram=%d, noanon=%d, noamap=%d, pgwait=%d, pgrele=%d\n", 318 uexp.fltnoram, uexp.fltnoanon, uexp.fltnoamap, 319 uexp.fltpgwait, uexp.fltpgrele); 320 (*pr)(" ok relocks(total)=%d(%d), anget(retries)=%d(%d), " 321 "amapcopy=%d\n", uexp.fltrelckok, uexp.fltrelck, 322 uexp.fltanget, uexp.fltanretry, uexp.fltamcopy); 323 (*pr)(" neighbor anon/obj pg=%d/%d, gets(lock/unlock)=%d/%d\n", 324 uexp.fltnamap, uexp.fltnomap, uexp.fltlget, uexp.fltget); 325 (*pr)(" cases: anon=%d, anoncow=%d, obj=%d, prcopy=%d, przero=%d\n", 326 uexp.flt_anon, uexp.flt_acow, uexp.flt_obj, uexp.flt_prcopy, 327 uexp.flt_przero); 328 329 (*pr)(" daemon and swap counts:\n"); 330 (*pr)(" woke=%d, revs=%d, scans=%d, obscans=%d, anscans=%d\n", 331 uexp.pdwoke, uexp.pdrevs, uexp.pdscans, uexp.pdobscan, 332 uexp.pdanscan); 333 (*pr)(" busy=%d, freed=%d, reactivate=%d, deactivate=%d\n", 334 uexp.pdbusy, uexp.pdfreed, uexp.pdreact, uexp.pddeact); 335 (*pr)(" pageouts=%d, pending=%d, nswget=%d\n", uexp.pdpageouts, 336 uexp.pdpending, uexp.nswget); 337 (*pr)(" nswapdev=%d\n", 338 uexp.nswapdev); 339 (*pr)(" swpages=%d, swpginuse=%d, swpgonly=%d paging=%d\n", 340 uexp.swpages, uexp.swpginuse, uexp.swpgonly, uexp.paging); 341 342 (*pr)(" kernel pointers:\n"); 343 (*pr)(" objs(kern)=%p\n", uvm.kernel_object); 344} 345#endif 346