1 /* $OpenBSD: uvm_meter.c,v 1.36 2015/03/14 03:38:53 jsg 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/proc.h> 43 #include <sys/sysctl.h> 44 #include <sys/vmmeter.h> 45 #include <uvm/uvm.h> 46 47 #ifdef UVM_SWAP_ENCRYPT 48 #include <uvm/uvm_swap.h> 49 #include <uvm/uvm_swap_encrypt.h> 50 #endif 51 52 /* 53 * The time for a process to be blocked before being very swappable. 54 * This is a number of seconds which the system takes as being a non-trivial 55 * amount of real time. You probably shouldn't change this; 56 * it is used in subtle ways (fractions and multiples of it are, that is, like 57 * half of a ``long time'', almost a long time, etc.) 58 * It is related to human patience and other factors which don't really 59 * change over time. 60 */ 61 #define MAXSLP 20 62 63 int maxslp = MAXSLP; /* patchable ... */ 64 struct loadavg averunnable; 65 66 /* 67 * constants for averages over 1, 5, and 15 minutes when sampling at 68 * 5 second intervals. 69 */ 70 71 static fixpt_t cexp[3] = { 72 0.9200444146293232 * FSCALE, /* exp(-1/12) */ 73 0.9834714538216174 * FSCALE, /* exp(-1/60) */ 74 0.9944598480048967 * FSCALE, /* exp(-1/180) */ 75 }; 76 77 78 static void uvm_loadav(struct loadavg *); 79 void uvm_total(struct vmtotal *); 80 81 /* 82 * uvm_meter: calculate load average and wake up the swapper (if needed) 83 */ 84 void 85 uvm_meter(void) 86 { 87 if ((time_second % 5) == 0) 88 uvm_loadav(&averunnable); 89 if (proc0.p_slptime > (maxslp / 2)) 90 wakeup(&proc0); 91 } 92 93 /* 94 * uvm_loadav: compute a tenex style load average of a quantity on 95 * 1, 5, and 15 minute intervals. 96 */ 97 static void 98 uvm_loadav(struct loadavg *avg) 99 { 100 CPU_INFO_ITERATOR cii; 101 struct cpu_info *ci; 102 int i, nrun; 103 struct proc *p; 104 int nrun_cpu[MAXCPUS]; 105 106 nrun = 0; 107 memset(nrun_cpu, 0, sizeof(nrun_cpu)); 108 109 LIST_FOREACH(p, &allproc, p_list) { 110 switch (p->p_stat) { 111 case SSLEEP: 112 if (p->p_priority > PZERO || p->p_slptime > 1) 113 continue; 114 /* FALLTHROUGH */ 115 case SRUN: 116 case SONPROC: 117 if (p == p->p_cpu->ci_schedstate.spc_idleproc) 118 continue; 119 case SIDL: 120 nrun++; 121 if (p->p_cpu) 122 nrun_cpu[CPU_INFO_UNIT(p->p_cpu)]++; 123 } 124 } 125 126 for (i = 0; i < 3; i++) { 127 avg->ldavg[i] = (cexp[i] * avg->ldavg[i] + 128 nrun * FSCALE * (FSCALE - cexp[i])) >> FSHIFT; 129 } 130 131 CPU_INFO_FOREACH(cii, ci) { 132 struct schedstate_percpu *spc = &ci->ci_schedstate; 133 134 if (nrun_cpu[CPU_INFO_UNIT(ci)] == 0) 135 continue; 136 spc->spc_ldavg = (cexp[0] * spc->spc_ldavg + 137 nrun_cpu[CPU_INFO_UNIT(ci)] * FSCALE * 138 (FSCALE - cexp[0])) >> FSHIFT; 139 } 140 } 141 142 /* 143 * uvm_sysctl: sysctl hook into UVM system. 144 */ 145 int 146 uvm_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, 147 size_t newlen, struct proc *p) 148 { 149 struct process *pr = p->p_p; 150 struct vmtotal vmtotals; 151 int rv, t; 152 153 switch (name[0]) { 154 case VM_SWAPENCRYPT: 155 #ifdef UVM_SWAP_ENCRYPT 156 return (swap_encrypt_ctl(name + 1, namelen - 1, oldp, oldlenp, 157 newp, newlen, p)); 158 #else 159 return (EOPNOTSUPP); 160 #endif 161 default: 162 /* all sysctl names at this level are terminal */ 163 if (namelen != 1) 164 return (ENOTDIR); /* overloaded */ 165 break; 166 } 167 168 switch (name[0]) { 169 case VM_LOADAVG: 170 return (sysctl_rdstruct(oldp, oldlenp, newp, &averunnable, 171 sizeof(averunnable))); 172 173 case VM_METER: 174 uvm_total(&vmtotals); 175 return (sysctl_rdstruct(oldp, oldlenp, newp, &vmtotals, 176 sizeof(vmtotals))); 177 178 case VM_UVMEXP: 179 return (sysctl_rdstruct(oldp, oldlenp, newp, &uvmexp, 180 sizeof(uvmexp))); 181 182 case VM_NKMEMPAGES: 183 return (sysctl_rdint(oldp, oldlenp, newp, nkmempages)); 184 185 case VM_PSSTRINGS: 186 return (sysctl_rdstruct(oldp, oldlenp, newp, &pr->ps_strings, 187 sizeof(pr->ps_strings))); 188 189 case VM_ANONMIN: 190 t = uvmexp.anonminpct; 191 rv = sysctl_int(oldp, oldlenp, newp, newlen, &t); 192 if (rv) { 193 return rv; 194 } 195 if (t + uvmexp.vtextminpct + uvmexp.vnodeminpct > 95 || t < 0) { 196 return EINVAL; 197 } 198 uvmexp.anonminpct = t; 199 uvmexp.anonmin = t * 256 / 100; 200 return rv; 201 202 case VM_VTEXTMIN: 203 t = uvmexp.vtextminpct; 204 rv = sysctl_int(oldp, oldlenp, newp, newlen, &t); 205 if (rv) { 206 return rv; 207 } 208 if (uvmexp.anonminpct + t + uvmexp.vnodeminpct > 95 || t < 0) { 209 return EINVAL; 210 } 211 uvmexp.vtextminpct = t; 212 uvmexp.vtextmin = t * 256 / 100; 213 return rv; 214 215 case VM_VNODEMIN: 216 t = uvmexp.vnodeminpct; 217 rv = sysctl_int(oldp, oldlenp, newp, newlen, &t); 218 if (rv) { 219 return rv; 220 } 221 if (uvmexp.anonminpct + uvmexp.vtextminpct + t > 95 || t < 0) { 222 return EINVAL; 223 } 224 uvmexp.vnodeminpct = t; 225 uvmexp.vnodemin = t * 256 / 100; 226 return rv; 227 228 case VM_MAXSLP: 229 return (sysctl_rdint(oldp, oldlenp, newp, maxslp)); 230 231 case VM_USPACE: 232 return (sysctl_rdint(oldp, oldlenp, newp, USPACE)); 233 234 default: 235 return (EOPNOTSUPP); 236 } 237 /* NOTREACHED */ 238 } 239 240 /* 241 * uvm_total: calculate the current state of the system. 242 */ 243 void 244 uvm_total(struct vmtotal *totalp) 245 { 246 struct proc *p; 247 #if 0 248 struct vm_map_entry * entry; 249 struct vm_map *map; 250 int paging; 251 #endif 252 253 memset(totalp, 0, sizeof *totalp); 254 255 /* calculate process statistics */ 256 LIST_FOREACH(p, &allproc, p_list) { 257 if (p->p_flag & P_SYSTEM) 258 continue; 259 switch (p->p_stat) { 260 case 0: 261 continue; 262 263 case SSLEEP: 264 case SSTOP: 265 if (p->p_priority <= PZERO) 266 totalp->t_dw++; 267 else if (p->p_slptime < maxslp) 268 totalp->t_sl++; 269 if (p->p_slptime >= maxslp) 270 continue; 271 break; 272 case SRUN: 273 case SIDL: 274 case SONPROC: 275 totalp->t_rq++; 276 if (p->p_stat == SIDL) 277 continue; 278 break; 279 } 280 /* 281 * note active objects 282 */ 283 #if 0 284 /* 285 * XXXCDC: BOGUS! rethink this. in the mean time 286 * don't do it. 287 */ 288 paging = 0; 289 vm_map_lock(map); 290 for (map = &p->p_vmspace->vm_map, entry = map->header.next; 291 entry != &map->header; entry = entry->next) { 292 if (entry->is_a_map || entry->is_sub_map || 293 entry->object.uvm_obj == NULL) 294 continue; 295 /* XXX how to do this with uvm */ 296 } 297 vm_map_unlock(map); 298 if (paging) 299 totalp->t_pw++; 300 #endif 301 } 302 /* 303 * Calculate object memory usage statistics. 304 */ 305 totalp->t_free = uvmexp.free; 306 totalp->t_vm = uvmexp.npages - uvmexp.free + uvmexp.swpginuse; 307 totalp->t_avm = uvmexp.active + uvmexp.swpginuse; /* XXX */ 308 totalp->t_rm = uvmexp.npages - uvmexp.free; 309 totalp->t_arm = uvmexp.active; 310 totalp->t_vmshr = 0; /* XXX */ 311 totalp->t_avmshr = 0; /* XXX */ 312 totalp->t_rmshr = 0; /* XXX */ 313 totalp->t_armshr = 0; /* XXX */ 314 } 315