1 /* $OpenBSD: uvm_meter.c,v 1.30 2013/03/23 16:12:31 deraadt 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. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by Charles D. Cranor, 22 * Washington University, and the University of California, Berkeley 23 * and its contributors. 24 * 4. Neither the name of the University nor the names of its contributors 25 * may be used to endorse or promote products derived from this software 26 * without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 * 40 * @(#)vm_meter.c 8.4 (Berkeley) 1/4/94 41 * from: Id: uvm_meter.c,v 1.1.2.1 1997/08/14 19:10:35 chuck Exp 42 */ 43 44 #include <sys/param.h> 45 #include <sys/proc.h> 46 #include <sys/systm.h> 47 #include <sys/kernel.h> 48 #include <uvm/uvm_extern.h> 49 #include <sys/sysctl.h> 50 #include <sys/exec.h> 51 52 #ifdef UVM_SWAP_ENCRYPT 53 #include <uvm/uvm_swap.h> 54 #include <uvm/uvm_swap_encrypt.h> 55 #endif 56 57 /* 58 * The time for a process to be blocked before being very swappable. 59 * This is a number of seconds which the system takes as being a non-trivial 60 * amount of real time. You probably shouldn't change this; 61 * it is used in subtle ways (fractions and multiples of it are, that is, like 62 * half of a ``long time'', almost a long time, etc.) 63 * It is related to human patience and other factors which don't really 64 * change over time. 65 */ 66 #define MAXSLP 20 67 68 int maxslp = MAXSLP; /* patchable ... */ 69 struct loadavg averunnable; 70 71 /* 72 * constants for averages over 1, 5, and 15 minutes when sampling at 73 * 5 second intervals. 74 */ 75 76 static fixpt_t cexp[3] = { 77 0.9200444146293232 * FSCALE, /* exp(-1/12) */ 78 0.9834714538216174 * FSCALE, /* exp(-1/60) */ 79 0.9944598480048967 * FSCALE, /* exp(-1/180) */ 80 }; 81 82 /* 83 * prototypes 84 */ 85 86 static void uvm_loadav(struct loadavg *); 87 88 /* 89 * uvm_meter: calculate load average and wake up the swapper (if needed) 90 */ 91 void 92 uvm_meter(void) 93 { 94 if ((time_second % 5) == 0) 95 uvm_loadav(&averunnable); 96 if (proc0.p_slptime > (maxslp / 2)) 97 wakeup(&proc0); 98 } 99 100 /* 101 * uvm_loadav: compute a tenex style load average of a quantity on 102 * 1, 5, and 15 minute intervals. 103 */ 104 static void 105 uvm_loadav(struct loadavg *avg) 106 { 107 CPU_INFO_ITERATOR cii; 108 struct cpu_info *ci; 109 int i, nrun; 110 struct proc *p; 111 int nrun_cpu[MAXCPUS]; 112 113 nrun = 0; 114 memset(nrun_cpu, 0, sizeof(nrun_cpu)); 115 116 LIST_FOREACH(p, &allproc, p_list) { 117 switch (p->p_stat) { 118 case SSLEEP: 119 if (p->p_priority > PZERO || p->p_slptime > 1) 120 continue; 121 /* FALLTHROUGH */ 122 case SRUN: 123 case SONPROC: 124 if (p == p->p_cpu->ci_schedstate.spc_idleproc) 125 continue; 126 case SIDL: 127 nrun++; 128 if (p->p_cpu) 129 nrun_cpu[CPU_INFO_UNIT(p->p_cpu)]++; 130 } 131 } 132 133 for (i = 0; i < 3; i++) { 134 avg->ldavg[i] = (cexp[i] * avg->ldavg[i] + 135 nrun * FSCALE * (FSCALE - cexp[i])) >> FSHIFT; 136 } 137 138 CPU_INFO_FOREACH(cii, ci) { 139 struct schedstate_percpu *spc = &ci->ci_schedstate; 140 141 if (nrun_cpu[CPU_INFO_UNIT(ci)] == 0) 142 continue; 143 spc->spc_ldavg = (cexp[0] * spc->spc_ldavg + 144 nrun_cpu[CPU_INFO_UNIT(ci)] * FSCALE * 145 (FSCALE - cexp[0])) >> FSHIFT; 146 } 147 } 148 149 /* 150 * uvm_sysctl: sysctl hook into UVM system. 151 */ 152 int 153 uvm_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, 154 size_t newlen, struct proc *p) 155 { 156 struct vmtotal vmtotals; 157 int rv, t; 158 struct _ps_strings _ps = { PS_STRINGS }; 159 160 switch (name[0]) { 161 case VM_SWAPENCRYPT: 162 #ifdef UVM_SWAP_ENCRYPT 163 return (swap_encrypt_ctl(name + 1, namelen - 1, oldp, oldlenp, 164 newp, newlen, p)); 165 #else 166 return (EOPNOTSUPP); 167 #endif 168 default: 169 /* all sysctl names at this level are terminal */ 170 if (namelen != 1) 171 return (ENOTDIR); /* overloaded */ 172 break; 173 } 174 175 switch (name[0]) { 176 case VM_LOADAVG: 177 return (sysctl_rdstruct(oldp, oldlenp, newp, &averunnable, 178 sizeof(averunnable))); 179 180 case VM_METER: 181 uvm_total(&vmtotals); 182 return (sysctl_rdstruct(oldp, oldlenp, newp, &vmtotals, 183 sizeof(vmtotals))); 184 185 case VM_UVMEXP: 186 return (sysctl_rdstruct(oldp, oldlenp, newp, &uvmexp, 187 sizeof(uvmexp))); 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, &_ps, 194 sizeof(_ps))); 195 case VM_ANONMIN: 196 t = uvmexp.anonminpct; 197 rv = sysctl_int(oldp, oldlenp, newp, newlen, &t); 198 if (rv) { 199 return rv; 200 } 201 if (t + uvmexp.vtextminpct + uvmexp.vnodeminpct > 95 || t < 0) { 202 return EINVAL; 203 } 204 uvmexp.anonminpct = t; 205 uvmexp.anonmin = t * 256 / 100; 206 return rv; 207 208 case VM_VTEXTMIN: 209 t = uvmexp.vtextminpct; 210 rv = sysctl_int(oldp, oldlenp, newp, newlen, &t); 211 if (rv) { 212 return rv; 213 } 214 if (uvmexp.anonminpct + t + uvmexp.vnodeminpct > 95 || t < 0) { 215 return EINVAL; 216 } 217 uvmexp.vtextminpct = t; 218 uvmexp.vtextmin = t * 256 / 100; 219 return rv; 220 221 case VM_VNODEMIN: 222 t = uvmexp.vnodeminpct; 223 rv = sysctl_int(oldp, oldlenp, newp, newlen, &t); 224 if (rv) { 225 return rv; 226 } 227 if (uvmexp.anonminpct + uvmexp.vtextminpct + t > 95 || t < 0) { 228 return EINVAL; 229 } 230 uvmexp.vnodeminpct = t; 231 uvmexp.vnodemin = t * 256 / 100; 232 return rv; 233 234 case VM_MAXSLP: 235 return (sysctl_rdint(oldp, oldlenp, newp, maxslp)); 236 237 case VM_USPACE: 238 return (sysctl_rdint(oldp, oldlenp, newp, USPACE)); 239 240 default: 241 return (EOPNOTSUPP); 242 } 243 /* NOTREACHED */ 244 } 245 246 /* 247 * uvm_total: calculate the current state of the system. 248 */ 249 void 250 uvm_total(struct vmtotal *totalp) 251 { 252 struct proc *p; 253 #if 0 254 struct vm_map_entry * entry; 255 struct vm_map *map; 256 int paging; 257 #endif 258 259 memset(totalp, 0, sizeof *totalp); 260 261 /* 262 * calculate process statistics 263 */ 264 265 LIST_FOREACH(p, &allproc, p_list) { 266 if (p->p_flag & P_SYSTEM) 267 continue; 268 switch (p->p_stat) { 269 case 0: 270 continue; 271 272 case SSLEEP: 273 case SSTOP: 274 if (p->p_priority <= PZERO) 275 totalp->t_dw++; 276 else if (p->p_slptime < maxslp) 277 totalp->t_sl++; 278 if (p->p_slptime >= maxslp) 279 continue; 280 break; 281 282 case SRUN: 283 case SIDL: 284 case SONPROC: 285 totalp->t_rq++; 286 if (p->p_stat == SIDL) 287 continue; 288 break; 289 } 290 /* 291 * note active objects 292 */ 293 #if 0 294 /* 295 * XXXCDC: BOGUS! rethink this. in the mean time 296 * don't do it. 297 */ 298 paging = 0; 299 vm_map_lock(map); 300 for (map = &p->p_vmspace->vm_map, entry = map->header.next; 301 entry != &map->header; entry = entry->next) { 302 if (entry->is_a_map || entry->is_sub_map || 303 entry->object.uvm_obj == NULL) 304 continue; 305 /* XXX how to do this with uvm */ 306 } 307 vm_map_unlock(map); 308 if (paging) 309 totalp->t_pw++; 310 #endif 311 } 312 /* 313 * Calculate object memory usage statistics. 314 */ 315 totalp->t_free = uvmexp.free; 316 totalp->t_vm = uvmexp.npages - uvmexp.free + uvmexp.swpginuse; 317 totalp->t_avm = uvmexp.active + uvmexp.swpginuse; /* XXX */ 318 totalp->t_rm = uvmexp.npages - uvmexp.free; 319 totalp->t_arm = uvmexp.active; 320 totalp->t_vmshr = 0; /* XXX */ 321 totalp->t_avmshr = 0; /* XXX */ 322 totalp->t_rmshr = 0; /* XXX */ 323 totalp->t_armshr = 0; /* XXX */ 324 } 325