1 /* $NetBSD: uvm_meter.c,v 1.37 2005/12/11 12:25:29 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1997 Charles D. Cranor and Washington University. 5 * Copyright (c) 1982, 1986, 1989, 1993 6 * The Regents of the University of California. 7 * 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by Charles D. Cranor, 21 * Washington University, and the University of California, Berkeley 22 * and its contributors. 23 * 4. Neither the name of the University nor the names of its contributors 24 * may be used to endorse or promote products derived from this software 25 * without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37 * SUCH DAMAGE. 38 * 39 * @(#)vm_meter.c 8.4 (Berkeley) 1/4/94 40 * from: Id: uvm_meter.c,v 1.1.2.1 1997/08/14 19:10:35 chuck Exp 41 */ 42 43 #include <sys/cdefs.h> 44 __KERNEL_RCSID(0, "$NetBSD: uvm_meter.c,v 1.37 2005/12/11 12:25:29 christos Exp $"); 45 46 #include <sys/param.h> 47 #include <sys/proc.h> 48 #include <sys/systm.h> 49 #include <sys/kernel.h> 50 #include <uvm/uvm_extern.h> 51 #include <sys/sysctl.h> 52 53 /* 54 * maxslp: ???? XXXCDC 55 */ 56 57 int maxslp = MAXSLP; /* patchable ... */ 58 struct loadavg averunnable; 59 60 /* 61 * constants for averages over 1, 5, and 15 minutes when sampling at 62 * 5 second intervals. 63 */ 64 65 static const fixpt_t cexp[3] = { 66 0.9200444146293232 * FSCALE, /* exp(-1/12) */ 67 0.9834714538216174 * FSCALE, /* exp(-1/60) */ 68 0.9944598480048967 * FSCALE, /* exp(-1/180) */ 69 }; 70 71 /* 72 * prototypes 73 */ 74 75 static void uvm_loadav(struct loadavg *); 76 static void uvm_total(struct vmtotal *); 77 78 /* 79 * uvm_meter: calculate load average and wake up the swapper (if needed) 80 */ 81 void 82 uvm_meter(void) 83 { 84 if ((time.tv_sec % 5) == 0) 85 uvm_loadav(&averunnable); 86 if (lwp0.l_slptime > (maxslp / 2)) 87 wakeup(&proc0); 88 } 89 90 /* 91 * uvm_loadav: compute a tenex style load average of a quantity on 92 * 1, 5, and 15 minute internvals. 93 */ 94 static void 95 uvm_loadav(struct loadavg *avg) 96 { 97 int i, nrun; 98 struct lwp *l; 99 100 proclist_lock_read(); 101 nrun = 0; 102 LIST_FOREACH(l, &alllwp, l_list) { 103 switch (l->l_stat) { 104 case LSSLEEP: 105 if (l->l_priority > PZERO || l->l_slptime > 1) 106 continue; 107 /* fall through */ 108 case LSRUN: 109 case LSONPROC: 110 case LSIDL: 111 nrun++; 112 } 113 } 114 proclist_unlock_read(); 115 for (i = 0; i < 3; i++) 116 avg->ldavg[i] = (cexp[i] * avg->ldavg[i] + 117 nrun * FSCALE * (FSCALE - cexp[i])) >> FSHIFT; 118 } 119 120 /* 121 * sysctl helper routine for the vm.vmmeter node. 122 */ 123 static int 124 sysctl_vm_meter(SYSCTLFN_ARGS) 125 { 126 struct sysctlnode node; 127 struct vmtotal vmtotals; 128 129 node = *rnode; 130 node.sysctl_data = &vmtotals; 131 uvm_total(&vmtotals); 132 133 return (sysctl_lookup(SYSCTLFN_CALL(&node))); 134 } 135 136 /* 137 * sysctl helper routine for the vm.uvmexp node. 138 */ 139 static int 140 sysctl_vm_uvmexp(SYSCTLFN_ARGS) 141 { 142 struct sysctlnode node; 143 144 node = *rnode; 145 if (oldp) 146 node.sysctl_size = min(*oldlenp, node.sysctl_size); 147 148 return (sysctl_lookup(SYSCTLFN_CALL(&node))); 149 } 150 151 static int 152 sysctl_vm_uvmexp2(SYSCTLFN_ARGS) 153 { 154 struct sysctlnode node; 155 struct uvmexp_sysctl u; 156 157 memset(&u, 0, sizeof(u)); 158 159 /* Entries here are in order of uvmexp_sysctl, not uvmexp */ 160 u.pagesize = uvmexp.pagesize; 161 u.pagemask = uvmexp.pagemask; 162 u.pageshift = uvmexp.pageshift; 163 u.npages = uvmexp.npages; 164 u.free = uvmexp.free; 165 u.active = uvmexp.active; 166 u.inactive = uvmexp.inactive; 167 u.paging = uvmexp.paging; 168 u.wired = uvmexp.wired; 169 u.zeropages = uvmexp.zeropages; 170 u.reserve_pagedaemon = uvmexp.reserve_pagedaemon; 171 u.reserve_kernel = uvmexp.reserve_kernel; 172 u.freemin = uvmexp.freemin; 173 u.freetarg = uvmexp.freetarg; 174 u.inactarg = uvmexp.inactarg; 175 u.wiredmax = uvmexp.wiredmax; 176 u.nswapdev = uvmexp.nswapdev; 177 u.swpages = uvmexp.swpages; 178 u.swpginuse = uvmexp.swpginuse; 179 u.swpgonly = uvmexp.swpgonly; 180 u.nswget = uvmexp.nswget; 181 u.faults = uvmexp.faults; 182 u.traps = uvmexp.traps; 183 u.intrs = uvmexp.intrs; 184 u.swtch = uvmexp.swtch; 185 u.softs = uvmexp.softs; 186 u.syscalls = uvmexp.syscalls; 187 u.pageins = uvmexp.pageins; 188 u.swapins = uvmexp.swapins; 189 u.swapouts = uvmexp.swapouts; 190 u.pgswapin = uvmexp.pgswapin; 191 u.pgswapout = uvmexp.pgswapout; 192 u.forks = uvmexp.forks; 193 u.forks_ppwait = uvmexp.forks_ppwait; 194 u.forks_sharevm = uvmexp.forks_sharevm; 195 u.pga_zerohit = uvmexp.pga_zerohit; 196 u.pga_zeromiss = uvmexp.pga_zeromiss; 197 u.zeroaborts = uvmexp.zeroaborts; 198 u.fltnoram = uvmexp.fltnoram; 199 u.fltnoanon = uvmexp.fltnoanon; 200 u.fltpgwait = uvmexp.fltpgwait; 201 u.fltpgrele = uvmexp.fltpgrele; 202 u.fltrelck = uvmexp.fltrelck; 203 u.fltrelckok = uvmexp.fltrelckok; 204 u.fltanget = uvmexp.fltanget; 205 u.fltanretry = uvmexp.fltanretry; 206 u.fltamcopy = uvmexp.fltamcopy; 207 u.fltnamap = uvmexp.fltnamap; 208 u.fltnomap = uvmexp.fltnomap; 209 u.fltlget = uvmexp.fltlget; 210 u.fltget = uvmexp.fltget; 211 u.flt_anon = uvmexp.flt_anon; 212 u.flt_acow = uvmexp.flt_acow; 213 u.flt_obj = uvmexp.flt_obj; 214 u.flt_prcopy = uvmexp.flt_prcopy; 215 u.flt_przero = uvmexp.flt_przero; 216 u.pdwoke = uvmexp.pdwoke; 217 u.pdrevs = uvmexp.pdrevs; 218 u.pdswout = uvmexp.pdswout; 219 u.pdfreed = uvmexp.pdfreed; 220 u.pdscans = uvmexp.pdscans; 221 u.pdanscan = uvmexp.pdanscan; 222 u.pdobscan = uvmexp.pdobscan; 223 u.pdreact = uvmexp.pdreact; 224 u.pdbusy = uvmexp.pdbusy; 225 u.pdpageouts = uvmexp.pdpageouts; 226 u.pdpending = uvmexp.pdpending; 227 u.pddeact = uvmexp.pddeact; 228 u.anonpages = uvmexp.anonpages; 229 u.filepages = uvmexp.filepages; 230 u.execpages = uvmexp.execpages; 231 u.colorhit = uvmexp.colorhit; 232 u.colormiss = uvmexp.colormiss; 233 234 node = *rnode; 235 node.sysctl_data = &u; 236 node.sysctl_size = sizeof(u); 237 return (sysctl_lookup(SYSCTLFN_CALL(&node))); 238 } 239 240 /* 241 * sysctl helper routine for the vm.{anon,exec,file}{min,max} nodes. 242 * makes sure that they all correlate properly and none are set too 243 * large. 244 */ 245 static int 246 sysctl_vm_updateminmax(SYSCTLFN_ARGS) 247 { 248 int t, error; 249 struct sysctlnode node; 250 251 node = *rnode; 252 node.sysctl_data = &t; 253 t = *(int*)rnode->sysctl_data; 254 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 255 if (error || newp == NULL) 256 return (error); 257 258 if (t < 0 || t > 100) 259 return (EINVAL); 260 261 #define UPDATEMIN(a, ap, bp, cp, tp) do { \ 262 if (tp + uvmexp.bp + uvmexp.cp > 95) \ 263 return (EINVAL); \ 264 uvmexp.ap = tp; \ 265 uvmexp.a = uvmexp.ap * 256 / 100; \ 266 } while (0/*CONSTCOND*/) 267 268 #define UPDATEMAX(a, ap, tp) do { \ 269 uvmexp.ap = tp; \ 270 uvmexp.a = tp * 256 / 100; \ 271 } while (0/*CONSTCOND*/) 272 273 switch (rnode->sysctl_num) { 274 case VM_ANONMIN: 275 UPDATEMIN(anonmin, anonminpct, fileminpct, execminpct, t); 276 break; 277 case VM_EXECMIN: 278 UPDATEMIN(execmin, execminpct, anonminpct, fileminpct, t); 279 break; 280 case VM_FILEMIN: 281 UPDATEMIN(filemin, fileminpct, execminpct, anonminpct, t); 282 break; 283 case VM_ANONMAX: 284 UPDATEMAX(anonmax, anonmaxpct, t); 285 break; 286 case VM_EXECMAX: 287 UPDATEMAX(execmax, execmaxpct, t); 288 break; 289 case VM_FILEMAX: 290 UPDATEMAX(filemax, filemaxpct, t); 291 break; 292 default: 293 return (EINVAL); 294 } 295 296 #undef UPDATEMIN 297 #undef UPDATEMAX 298 299 return (0); 300 } 301 302 /* 303 * uvm_sysctl: sysctl hook into UVM system. 304 */ 305 SYSCTL_SETUP(sysctl_vm_setup, "sysctl vm subtree setup") 306 { 307 308 sysctl_createv(clog, 0, NULL, NULL, 309 CTLFLAG_PERMANENT, 310 CTLTYPE_NODE, "vm", NULL, 311 NULL, 0, NULL, 0, 312 CTL_VM, CTL_EOL); 313 sysctl_createv(clog, 0, NULL, NULL, 314 CTLFLAG_PERMANENT, 315 CTLTYPE_STRUCT, "vmmeter", 316 SYSCTL_DESCR("Simple system-wide virtual memory " 317 "statistics"), 318 sysctl_vm_meter, 0, NULL, sizeof(struct vmtotal), 319 CTL_VM, VM_METER, CTL_EOL); 320 sysctl_createv(clog, 0, NULL, NULL, 321 CTLFLAG_PERMANENT, 322 CTLTYPE_STRUCT, "loadavg", 323 SYSCTL_DESCR("System load average history"), 324 NULL, 0, &averunnable, sizeof(averunnable), 325 CTL_VM, VM_LOADAVG, CTL_EOL); 326 sysctl_createv(clog, 0, NULL, NULL, 327 CTLFLAG_PERMANENT, 328 CTLTYPE_STRUCT, "uvmexp", 329 SYSCTL_DESCR("Detailed system-wide virtual memory " 330 "statistics"), 331 sysctl_vm_uvmexp, 0, &uvmexp, sizeof(uvmexp), 332 CTL_VM, VM_UVMEXP, CTL_EOL); 333 sysctl_createv(clog, 0, NULL, NULL, 334 CTLFLAG_PERMANENT, 335 CTLTYPE_INT, "nkmempages", 336 SYSCTL_DESCR("Default number of pages in kmem_map"), 337 NULL, 0, &nkmempages, 0, 338 CTL_VM, VM_NKMEMPAGES, CTL_EOL); 339 sysctl_createv(clog, 0, NULL, NULL, 340 CTLFLAG_PERMANENT, 341 CTLTYPE_STRUCT, "uvmexp2", 342 SYSCTL_DESCR("Detailed system-wide virtual memory " 343 "statistics (MI)"), 344 sysctl_vm_uvmexp2, 0, NULL, 0, 345 CTL_VM, VM_UVMEXP2, CTL_EOL); 346 sysctl_createv(clog, 0, NULL, NULL, 347 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 348 CTLTYPE_INT, "anonmin", 349 SYSCTL_DESCR("Percentage of physical memory reserved " 350 "for anonymous application data"), 351 sysctl_vm_updateminmax, 0, &uvmexp.anonminpct, 0, 352 CTL_VM, VM_ANONMIN, CTL_EOL); 353 sysctl_createv(clog, 0, NULL, NULL, 354 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 355 CTLTYPE_INT, "execmin", 356 SYSCTL_DESCR("Percentage of physical memory reserved " 357 "for cached executable data"), 358 sysctl_vm_updateminmax, 0, &uvmexp.execminpct, 0, 359 CTL_VM, VM_EXECMIN, CTL_EOL); 360 sysctl_createv(clog, 0, NULL, NULL, 361 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 362 CTLTYPE_INT, "filemin", 363 SYSCTL_DESCR("Percentage of physical memory reserved " 364 "for cached file data"), 365 sysctl_vm_updateminmax, 0, &uvmexp.fileminpct, 0, 366 CTL_VM, VM_FILEMIN, CTL_EOL); 367 sysctl_createv(clog, 0, NULL, NULL, 368 CTLFLAG_PERMANENT, CTLTYPE_INT, "maxslp", 369 SYSCTL_DESCR("Maximum process sleep time before being " 370 "swapped"), 371 NULL, 0, &maxslp, 0, 372 CTL_VM, VM_MAXSLP, CTL_EOL); 373 sysctl_createv(clog, 0, NULL, NULL, 374 CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE, 375 CTLTYPE_INT, "uspace", 376 SYSCTL_DESCR("Number of bytes allocated for a kernel " 377 "stack"), 378 NULL, USPACE, NULL, 0, 379 CTL_VM, VM_USPACE, CTL_EOL); 380 sysctl_createv(clog, 0, NULL, NULL, 381 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 382 CTLTYPE_INT, "anonmax", 383 SYSCTL_DESCR("Percentage of physical memory which will " 384 "be reclaimed from other usage for " 385 "anonymous application data"), 386 sysctl_vm_updateminmax, 0, &uvmexp.anonmaxpct, 0, 387 CTL_VM, VM_ANONMAX, CTL_EOL); 388 sysctl_createv(clog, 0, NULL, NULL, 389 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 390 CTLTYPE_INT, "execmax", 391 SYSCTL_DESCR("Percentage of physical memory which will " 392 "be reclaimed from other usage for cached " 393 "executable data"), 394 sysctl_vm_updateminmax, 0, &uvmexp.execmaxpct, 0, 395 CTL_VM, VM_EXECMAX, CTL_EOL); 396 sysctl_createv(clog, 0, NULL, NULL, 397 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 398 CTLTYPE_INT, "filemax", 399 SYSCTL_DESCR("Percentage of physical memory which will " 400 "be reclaimed from other usage for cached " 401 "file data"), 402 sysctl_vm_updateminmax, 0, &uvmexp.filemaxpct, 0, 403 CTL_VM, VM_FILEMAX, CTL_EOL); 404 sysctl_createv(clog, 0, NULL, NULL, 405 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 406 CTLTYPE_INT, "idlezero", 407 SYSCTL_DESCR("Whether try to zero pages in idle loop"), 408 NULL, 0, &vm_page_zero_enable, 0, 409 CTL_VM, CTL_CREATE, CTL_EOL); 410 } 411 412 /* 413 * uvm_total: calculate the current state of the system. 414 */ 415 static void 416 uvm_total(struct vmtotal *totalp) 417 { 418 struct lwp *l; 419 #if 0 420 struct vm_map_entry * entry; 421 struct vm_map *map; 422 int paging; 423 #endif 424 425 memset(totalp, 0, sizeof *totalp); 426 427 /* 428 * calculate process statistics 429 */ 430 431 proclist_lock_read(); 432 LIST_FOREACH(l, &alllwp, l_list) { 433 if (l->l_proc->p_flag & P_SYSTEM) 434 continue; 435 switch (l->l_stat) { 436 case 0: 437 continue; 438 439 case LSSLEEP: 440 case LSSTOP: 441 if (l->l_flag & L_INMEM) { 442 if (l->l_priority <= PZERO) 443 totalp->t_dw++; 444 else if (l->l_slptime < maxslp) 445 totalp->t_sl++; 446 } else if (l->l_slptime < maxslp) 447 totalp->t_sw++; 448 if (l->l_slptime >= maxslp) 449 continue; 450 break; 451 452 case LSRUN: 453 case LSONPROC: 454 case LSIDL: 455 if (l->l_flag & L_INMEM) 456 totalp->t_rq++; 457 else 458 totalp->t_sw++; 459 if (l->l_stat == LSIDL) 460 continue; 461 break; 462 } 463 /* 464 * note active objects 465 */ 466 #if 0 467 /* 468 * XXXCDC: BOGUS! rethink this. in the mean time 469 * don't do it. 470 */ 471 paging = 0; 472 vm_map_lock(map); 473 for (map = &p->p_vmspace->vm_map, entry = map->header.next; 474 entry != &map->header; entry = entry->next) { 475 if (entry->is_a_map || entry->is_sub_map || 476 entry->object.uvm_obj == NULL) 477 continue; 478 /* XXX how to do this with uvm */ 479 } 480 vm_map_unlock(map); 481 if (paging) 482 totalp->t_pw++; 483 #endif 484 } 485 proclist_unlock_read(); 486 /* 487 * Calculate object memory usage statistics. 488 */ 489 totalp->t_free = uvmexp.free; 490 totalp->t_vm = uvmexp.npages - uvmexp.free + uvmexp.swpginuse; 491 totalp->t_avm = uvmexp.active + uvmexp.swpginuse; /* XXX */ 492 totalp->t_rm = uvmexp.npages - uvmexp.free; 493 totalp->t_arm = uvmexp.active; 494 totalp->t_vmshr = 0; /* XXX */ 495 totalp->t_avmshr = 0; /* XXX */ 496 totalp->t_rmshr = 0; /* XXX */ 497 totalp->t_armshr = 0; /* XXX */ 498 } 499