1 /* $OpenBSD: uvm_meter.c,v 1.17 2002/03/14 01:27:18 millert 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 * maxslp: ???? XXXCDC
59 */
60
61 int maxslp = MAXSLP; /* patchable ... */
62 struct loadavg averunnable;
63
64 extern int allowpse;
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 * prototypes
79 */
80
81 static void uvm_loadav(struct loadavg *);
82
83 /*
84 * uvm_meter: calculate load average and wake up the swapper (if needed)
85 */
86 void
uvm_meter()87 uvm_meter()
88 {
89 if ((time.tv_sec % 5) == 0)
90 uvm_loadav(&averunnable);
91 if (proc0.p_slptime > (maxslp / 2))
92 wakeup(&proc0);
93 }
94
95 /*
96 * uvm_loadav: compute a tenex style load average of a quantity on
97 * 1, 5, and 15 minute internvals.
98 */
99 static void
uvm_loadav(avg)100 uvm_loadav(avg)
101 struct loadavg *avg;
102 {
103 int i, nrun;
104 struct proc *p;
105
106 nrun = 0;
107 LIST_FOREACH(p, &allproc, p_list) {
108 switch (p->p_stat) {
109 case SSLEEP:
110 if (p->p_priority > PZERO || p->p_slptime > 1)
111 continue;
112 /* fall through */
113 case SRUN:
114 case SIDL:
115 nrun++;
116 }
117 }
118 for (i = 0; i < 3; i++)
119 avg->ldavg[i] = (cexp[i] * avg->ldavg[i] +
120 nrun * FSCALE * (FSCALE - cexp[i])) >> FSHIFT;
121 }
122
123 /*
124 * uvm_sysctl: sysctl hook into UVM system.
125 */
126 int
uvm_sysctl(name,namelen,oldp,oldlenp,newp,newlen,p)127 uvm_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
128 int *name;
129 u_int namelen;
130 void *oldp;
131 size_t *oldlenp;
132 void *newp;
133 size_t newlen;
134 struct proc *p;
135 {
136 struct vmtotal vmtotals;
137 int rv, t;
138 struct _ps_strings _ps = { PS_STRINGS };
139 struct proc *cur = curproc;
140
141 switch (name[0]) {
142 case VM_SWAPENCRYPT:
143 #ifdef UVM_SWAP_ENCRYPT
144 return (swap_encrypt_ctl(name + 1, namelen - 1, oldp, oldlenp,
145 newp, newlen, p));
146 #else
147 return (EOPNOTSUPP);
148 #endif
149 default:
150 /* all sysctl names at this level are terminal */
151 if (namelen != 1)
152 return (ENOTDIR); /* overloaded */
153 break;
154 }
155
156 switch (name[0]) {
157 case VM_LOADAVG:
158 return (sysctl_rdstruct(oldp, oldlenp, newp, &averunnable,
159 sizeof(averunnable)));
160
161 case VM_METER:
162 uvm_total(&vmtotals);
163 return (sysctl_rdstruct(oldp, oldlenp, newp, &vmtotals,
164 sizeof(vmtotals)));
165
166 case VM_UVMEXP:
167 return (sysctl_rdstruct(oldp, oldlenp, newp, &uvmexp,
168 sizeof(uvmexp)));
169
170 case VM_NKMEMPAGES:
171 return (sysctl_rdint(oldp, oldlenp, newp, nkmempages));
172
173 case VM_PSSTRINGS:
174 if ((!allowpse) &&
175 (cur->p_cred->p_ruid != p->p_cred->p_ruid) &&
176 (cur->p_cred->p_rgid))
177 return (EPERM);
178
179 return (sysctl_rdstruct(oldp, oldlenp, newp, &_ps,
180 sizeof(_ps)));
181 case VM_ANONMIN:
182 t = uvmexp.anonminpct;
183 rv = sysctl_int(oldp, oldlenp, newp, newlen, &t);
184 if (rv) {
185 return rv;
186 }
187 if (t + uvmexp.vtextminpct + uvmexp.vnodeminpct > 95 || t < 0) {
188 return EINVAL;
189 }
190 uvmexp.anonminpct = t;
191 uvmexp.anonmin = t * 256 / 100;
192 return rv;
193
194 case VM_VTEXTMIN:
195 t = uvmexp.vtextminpct;
196 rv = sysctl_int(oldp, oldlenp, newp, newlen, &t);
197 if (rv) {
198 return rv;
199 }
200 if (uvmexp.anonminpct + t + uvmexp.vnodeminpct > 95 || t < 0) {
201 return EINVAL;
202 }
203 uvmexp.vtextminpct = t;
204 uvmexp.vtextmin = t * 256 / 100;
205 return rv;
206
207 case VM_VNODEMIN:
208 t = uvmexp.vnodeminpct;
209 rv = sysctl_int(oldp, oldlenp, newp, newlen, &t);
210 if (rv) {
211 return rv;
212 }
213 if (uvmexp.anonminpct + uvmexp.vtextminpct + t > 95 || t < 0) {
214 return EINVAL;
215 }
216 uvmexp.vnodeminpct = t;
217 uvmexp.vnodemin = t * 256 / 100;
218 return rv;
219
220 case VM_MAXSLP:
221 return (sysctl_rdint(oldp, oldlenp, newp, maxslp));
222
223 case VM_USPACE:
224 return (sysctl_rdint(oldp, oldlenp, newp, USPACE));
225
226 default:
227 return (EOPNOTSUPP);
228 }
229 /* NOTREACHED */
230 }
231
232 /*
233 * uvm_total: calculate the current state of the system.
234 */
235 void
uvm_total(totalp)236 uvm_total(totalp)
237 struct vmtotal *totalp;
238 {
239 struct proc *p;
240 #if 0
241 struct vm_map_entry * entry;
242 struct vm_map *map;
243 int paging;
244 #endif
245
246 memset(totalp, 0, sizeof *totalp);
247
248 /*
249 * calculate process statistics
250 */
251
252 LIST_FOREACH(p, &allproc, p_list) {
253 if (p->p_flag & P_SYSTEM)
254 continue;
255 switch (p->p_stat) {
256 case 0:
257 continue;
258
259 case SSLEEP:
260 case SSTOP:
261 if (p->p_flag & P_INMEM) {
262 if (p->p_priority <= PZERO)
263 totalp->t_dw++;
264 else if (p->p_slptime < maxslp)
265 totalp->t_sl++;
266 } else if (p->p_slptime < maxslp)
267 totalp->t_sw++;
268 if (p->p_slptime >= maxslp)
269 continue;
270 break;
271
272 case SRUN:
273 case SIDL:
274 if (p->p_flag & P_INMEM)
275 totalp->t_rq++;
276 else
277 totalp->t_sw++;
278 if (p->p_stat == SIDL)
279 continue;
280 break;
281 }
282 /*
283 * note active objects
284 */
285 #if 0
286 /*
287 * XXXCDC: BOGUS! rethink this. in the mean time
288 * don't do it.
289 */
290 paging = 0;
291 vm_map_lock(map);
292 for (map = &p->p_vmspace->vm_map, entry = map->header.next;
293 entry != &map->header; entry = entry->next) {
294 if (entry->is_a_map || entry->is_sub_map ||
295 entry->object.uvm_obj == NULL)
296 continue;
297 /* XXX how to do this with uvm */
298 }
299 vm_map_unlock(map);
300 if (paging)
301 totalp->t_pw++;
302 #endif
303 }
304 /*
305 * Calculate object memory usage statistics.
306 */
307 totalp->t_free = uvmexp.free;
308 totalp->t_vm = uvmexp.npages - uvmexp.free + uvmexp.swpginuse;
309 totalp->t_avm = uvmexp.active + uvmexp.swpginuse; /* XXX */
310 totalp->t_rm = uvmexp.npages - uvmexp.free;
311 totalp->t_arm = uvmexp.active;
312 totalp->t_vmshr = 0; /* XXX */
313 totalp->t_avmshr = 0; /* XXX */
314 totalp->t_rmshr = 0; /* XXX */
315 totalp->t_armshr = 0; /* XXX */
316 }
317