1 /* $OpenBSD: uvm_meter.c,v 1.42 2020/12/28 14:01:23 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 65 int maxslp = MAXSLP; /* patchable ... */ 66 struct loadavg averunnable; 67 68 /* 69 * constants for averages over 1, 5, and 15 minutes when sampling at 70 * 5 second intervals. 71 */ 72 73 static fixpt_t cexp[3] = { 74 0.9200444146293232 * FSCALE, /* exp(-1/12) */ 75 0.9834714538216174 * FSCALE, /* exp(-1/60) */ 76 0.9944598480048967 * FSCALE, /* exp(-1/180) */ 77 }; 78 79 80 static void uvm_loadav(struct loadavg *); 81 void uvm_total(struct vmtotal *); 82 void uvmexp_read(struct uvmexp *); 83 84 /* 85 * uvm_meter: calculate load average and wake up the swapper (if needed) 86 */ 87 void 88 uvm_meter(void) 89 { 90 if ((gettime() % 5) == 0) 91 uvm_loadav(&averunnable); 92 if (proc0.p_slptime > (maxslp / 2)) 93 wakeup(&proc0); 94 } 95 96 /* 97 * uvm_loadav: compute a tenex style load average of a quantity on 98 * 1, 5, and 15 minute intervals. 99 */ 100 static void 101 uvm_loadav(struct loadavg *avg) 102 { 103 CPU_INFO_ITERATOR cii; 104 struct cpu_info *ci; 105 int i, nrun; 106 struct proc *p; 107 int nrun_cpu[MAXCPUS]; 108 109 nrun = 0; 110 memset(nrun_cpu, 0, sizeof(nrun_cpu)); 111 112 LIST_FOREACH(p, &allproc, p_list) { 113 switch (p->p_stat) { 114 case SSTOP: 115 case SSLEEP: 116 break; 117 case SRUN: 118 case SONPROC: 119 if (p == p->p_cpu->ci_schedstate.spc_idleproc) 120 continue; 121 /* FALLTHROUGH */ 122 case SIDL: 123 nrun++; 124 if (p->p_cpu) 125 nrun_cpu[CPU_INFO_UNIT(p->p_cpu)]++; 126 } 127 } 128 129 for (i = 0; i < 3; i++) { 130 avg->ldavg[i] = (cexp[i] * avg->ldavg[i] + 131 nrun * FSCALE * (FSCALE - cexp[i])) >> FSHIFT; 132 } 133 134 CPU_INFO_FOREACH(cii, ci) { 135 struct schedstate_percpu *spc = &ci->ci_schedstate; 136 137 if (nrun_cpu[CPU_INFO_UNIT(ci)] == 0) 138 continue; 139 spc->spc_ldavg = (cexp[0] * spc->spc_ldavg + 140 nrun_cpu[CPU_INFO_UNIT(ci)] * FSCALE * 141 (FSCALE - cexp[0])) >> FSHIFT; 142 } 143 } 144 145 char malloc_conf[16]; 146 147 /* 148 * uvm_sysctl: sysctl hook into UVM system. 149 */ 150 int 151 uvm_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, 152 size_t newlen, struct proc *p) 153 { 154 struct process *pr = p->p_p; 155 struct vmtotal vmtotals; 156 struct uvmexp uexp; 157 int rv, t; 158 159 switch (name[0]) { 160 case VM_SWAPENCRYPT: 161 #ifdef UVM_SWAP_ENCRYPT 162 return (swap_encrypt_ctl(name + 1, namelen - 1, oldp, oldlenp, 163 newp, newlen, p)); 164 #else 165 return (EOPNOTSUPP); 166 #endif 167 default: 168 /* all sysctl names at this level are terminal */ 169 if (namelen != 1) 170 return (ENOTDIR); /* overloaded */ 171 break; 172 } 173 174 switch (name[0]) { 175 case VM_LOADAVG: 176 return (sysctl_rdstruct(oldp, oldlenp, newp, &averunnable, 177 sizeof(averunnable))); 178 179 case VM_METER: 180 uvm_total(&vmtotals); 181 return (sysctl_rdstruct(oldp, oldlenp, newp, &vmtotals, 182 sizeof(vmtotals))); 183 184 case VM_UVMEXP: 185 uvmexp_read(&uexp); 186 return (sysctl_rdstruct(oldp, oldlenp, newp, &uexp, 187 sizeof(uexp))); 188 189 case VM_NKMEMPAGES: 190 return (sysctl_rdint(oldp, oldlenp, newp, nkmempages)); 191 192 case VM_PSSTRINGS: 193 return (sysctl_rdstruct(oldp, oldlenp, newp, &pr->ps_strings, 194 sizeof(pr->ps_strings))); 195 196 case VM_ANONMIN: 197 t = uvmexp.anonminpct; 198 rv = sysctl_int(oldp, oldlenp, newp, newlen, &t); 199 if (rv) { 200 return rv; 201 } 202 if (t + uvmexp.vtextminpct + uvmexp.vnodeminpct > 95 || t < 0) { 203 return EINVAL; 204 } 205 uvmexp.anonminpct = t; 206 uvmexp.anonmin = t * 256 / 100; 207 return rv; 208 209 case VM_VTEXTMIN: 210 t = uvmexp.vtextminpct; 211 rv = sysctl_int(oldp, oldlenp, newp, newlen, &t); 212 if (rv) { 213 return rv; 214 } 215 if (uvmexp.anonminpct + t + uvmexp.vnodeminpct > 95 || t < 0) { 216 return EINVAL; 217 } 218 uvmexp.vtextminpct = t; 219 uvmexp.vtextmin = t * 256 / 100; 220 return rv; 221 222 case VM_VNODEMIN: 223 t = uvmexp.vnodeminpct; 224 rv = sysctl_int(oldp, oldlenp, newp, newlen, &t); 225 if (rv) { 226 return rv; 227 } 228 if (uvmexp.anonminpct + uvmexp.vtextminpct + t > 95 || t < 0) { 229 return EINVAL; 230 } 231 uvmexp.vnodeminpct = t; 232 uvmexp.vnodemin = t * 256 / 100; 233 return rv; 234 235 case VM_MAXSLP: 236 return (sysctl_rdint(oldp, oldlenp, newp, maxslp)); 237 238 case VM_USPACE: 239 return (sysctl_rdint(oldp, oldlenp, newp, USPACE)); 240 241 case VM_MALLOC_CONF: 242 return (sysctl_string(oldp, oldlenp, newp, newlen, 243 malloc_conf, sizeof(malloc_conf))); 244 default: 245 return (EOPNOTSUPP); 246 } 247 /* NOTREACHED */ 248 } 249 250 /* 251 * uvm_total: calculate the current state of the system. 252 */ 253 void 254 uvm_total(struct vmtotal *totalp) 255 { 256 struct proc *p; 257 #if 0 258 struct vm_map_entry * entry; 259 struct vm_map *map; 260 int paging; 261 #endif 262 263 memset(totalp, 0, sizeof *totalp); 264 265 /* calculate process statistics */ 266 LIST_FOREACH(p, &allproc, p_list) { 267 switch (p->p_stat) { 268 case 0: 269 continue; 270 271 case SSLEEP: 272 case SSTOP: 273 totalp->t_sl++; 274 break; 275 case SRUN: 276 case SONPROC: 277 if (p == p->p_cpu->ci_schedstate.spc_idleproc) 278 continue; 279 /* FALLTHROUGH */ 280 case SIDL: 281 totalp->t_rq++; 282 if (p->p_stat == SIDL) 283 continue; 284 break; 285 } 286 /* 287 * note active objects 288 */ 289 #if 0 290 /* 291 * XXXCDC: BOGUS! rethink this. in the mean time 292 * don't do it. 293 */ 294 paging = 0; 295 vm_map_lock(map); 296 for (map = &p->p_vmspace->vm_map, entry = map->header.next; 297 entry != &map->header; entry = entry->next) { 298 if (entry->is_a_map || entry->is_sub_map || 299 entry->object.uvm_obj == NULL) 300 continue; 301 /* XXX how to do this with uvm */ 302 } 303 vm_map_unlock(map); 304 if (paging) 305 totalp->t_pw++; 306 #endif 307 } 308 /* 309 * Calculate object memory usage statistics. 310 */ 311 totalp->t_free = uvmexp.free; 312 totalp->t_vm = uvmexp.npages - uvmexp.free + uvmexp.swpginuse; 313 totalp->t_avm = uvmexp.active + uvmexp.swpginuse; /* XXX */ 314 totalp->t_rm = uvmexp.npages - uvmexp.free; 315 totalp->t_arm = uvmexp.active; 316 totalp->t_vmshr = 0; /* XXX */ 317 totalp->t_avmshr = 0; /* XXX */ 318 totalp->t_rmshr = 0; /* XXX */ 319 totalp->t_armshr = 0; /* XXX */ 320 } 321 322 void 323 uvmexp_read(struct uvmexp *uexp) 324 { 325 uint64_t counters[exp_ncounters]; 326 327 memcpy(uexp, &uvmexp, sizeof(*uexp)); 328 329 counters_read(uvmexp_counters, counters, exp_ncounters); 330 331 /* stat counters */ 332 uexp->faults = (int)counters[faults]; 333 uexp->pageins = (int)counters[pageins]; 334 335 /* fault subcounters */ 336 uexp->fltnoram = (int)counters[flt_noram]; 337 uexp->fltnoanon = (int)counters[flt_noanon]; 338 uexp->fltnoamap = (int)counters[flt_noamap]; 339 uexp->fltpgwait = (int)counters[flt_pgwait]; 340 uexp->fltpgrele = (int)counters[flt_pgrele]; 341 uexp->fltrelck = (int)counters[flt_relck]; 342 uexp->fltrelckok = (int)counters[flt_relckok]; 343 uexp->fltanget = (int)counters[flt_anget]; 344 uexp->fltanretry = (int)counters[flt_anretry]; 345 uexp->fltamcopy = (int)counters[flt_amcopy]; 346 uexp->fltnamap = (int)counters[flt_namap]; 347 uexp->fltnomap = (int)counters[flt_nomap]; 348 uexp->fltlget = (int)counters[flt_lget]; 349 uexp->fltget = (int)counters[flt_get]; 350 uexp->flt_anon = (int)counters[flt_anon]; 351 uexp->flt_acow = (int)counters[flt_acow]; 352 uexp->flt_obj = (int)counters[flt_obj]; 353 uexp->flt_prcopy = (int)counters[flt_prcopy]; 354 uexp->flt_przero = (int)counters[flt_przero]; 355 } 356 357 #ifdef DDB 358 359 /* 360 * uvmexp_print: ddb hook to print interesting uvm counters 361 */ 362 void 363 uvmexp_print(int (*pr)(const char *, ...)) 364 { 365 struct uvmexp uexp; 366 367 uvmexp_read(&uexp); 368 369 (*pr)("Current UVM status:\n"); 370 (*pr)(" pagesize=%d (0x%x), pagemask=0x%x, pageshift=%d\n", 371 uexp.pagesize, uexp.pagesize, uexp.pagemask, 372 uexp.pageshift); 373 (*pr)(" %d VM pages: %d active, %d inactive, %d wired, %d free (%d zero)\n", 374 uexp.npages, uexp.active, uexp.inactive, uexp.wired, 375 uexp.free, uexp.zeropages); 376 (*pr)(" min %d%% (%d) anon, %d%% (%d) vnode, %d%% (%d) vtext\n", 377 uexp.anonminpct, uexp.anonmin, uexp.vnodeminpct, 378 uexp.vnodemin, uexp.vtextminpct, uexp.vtextmin); 379 (*pr)(" freemin=%d, free-target=%d, inactive-target=%d, " 380 "wired-max=%d\n", uexp.freemin, uexp.freetarg, uexp.inactarg, 381 uexp.wiredmax); 382 (*pr)(" faults=%d, traps=%d, intrs=%d, ctxswitch=%d fpuswitch=%d\n", 383 uexp.faults, uexp.traps, uexp.intrs, uexp.swtch, 384 uexp.fpswtch); 385 (*pr)(" softint=%d, syscalls=%d, kmapent=%d\n", 386 uexp.softs, uexp.syscalls, uexp.kmapent); 387 388 (*pr)(" fault counts:\n"); 389 (*pr)(" noram=%d, noanon=%d, noamap=%d, pgwait=%d, pgrele=%d\n", 390 uexp.fltnoram, uexp.fltnoanon, uexp.fltnoamap, 391 uexp.fltpgwait, uexp.fltpgrele); 392 (*pr)(" ok relocks(total)=%d(%d), anget(retries)=%d(%d), " 393 "amapcopy=%d\n", uexp.fltrelckok, uexp.fltrelck, 394 uexp.fltanget, uexp.fltanretry, uexp.fltamcopy); 395 (*pr)(" neighbor anon/obj pg=%d/%d, gets(lock/unlock)=%d/%d\n", 396 uexp.fltnamap, uexp.fltnomap, uexp.fltlget, uexp.fltget); 397 (*pr)(" cases: anon=%d, anoncow=%d, obj=%d, prcopy=%d, przero=%d\n", 398 uexp.flt_anon, uexp.flt_acow, uexp.flt_obj, uexp.flt_prcopy, 399 uexp.flt_przero); 400 401 (*pr)(" daemon and swap counts:\n"); 402 (*pr)(" woke=%d, revs=%d, scans=%d, obscans=%d, anscans=%d\n", 403 uexp.pdwoke, uexp.pdrevs, uexp.pdscans, uexp.pdobscan, 404 uexp.pdanscan); 405 (*pr)(" busy=%d, freed=%d, reactivate=%d, deactivate=%d\n", 406 uexp.pdbusy, uexp.pdfreed, uexp.pdreact, uexp.pddeact); 407 (*pr)(" pageouts=%d, pending=%d, nswget=%d\n", uexp.pdpageouts, 408 uexp.pdpending, uexp.nswget); 409 (*pr)(" nswapdev=%d\n", 410 uexp.nswapdev); 411 (*pr)(" swpages=%d, swpginuse=%d, swpgonly=%d paging=%d\n", 412 uexp.swpages, uexp.swpginuse, uexp.swpgonly, uexp.paging); 413 414 (*pr)(" kernel pointers:\n"); 415 (*pr)(" objs(kern)=%p\n", uvm.kernel_object); 416 } 417 #endif 418