Line data Source code
1 : /* $OpenBSD: uvm_meter.c,v 1.37 2017/05/09 09:36:04 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/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 0 : uvm_meter(void)
86 : {
87 0 : if ((time_second % 5) == 0)
88 0 : uvm_loadav(&averunnable);
89 0 : if (proc0.p_slptime > (maxslp / 2))
90 0 : wakeup(&proc0);
91 0 : }
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 0 : 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 0 : int nrun_cpu[MAXCPUS];
105 :
106 : nrun = 0;
107 0 : memset(nrun_cpu, 0, sizeof(nrun_cpu));
108 :
109 0 : LIST_FOREACH(p, &allproc, p_list) {
110 0 : switch (p->p_stat) {
111 : case SSTOP:
112 : case SSLEEP:
113 : break;
114 : case SRUN:
115 : case SONPROC:
116 0 : if (p == p->p_cpu->ci_schedstate.spc_idleproc)
117 : continue;
118 : /* FALLTHROUGH */
119 : case SIDL:
120 0 : nrun++;
121 0 : if (p->p_cpu)
122 0 : nrun_cpu[CPU_INFO_UNIT(p->p_cpu)]++;
123 : }
124 : }
125 :
126 0 : for (i = 0; i < 3; i++) {
127 0 : avg->ldavg[i] = (cexp[i] * avg->ldavg[i] +
128 0 : nrun * FSCALE * (FSCALE - cexp[i])) >> FSHIFT;
129 : }
130 :
131 0 : CPU_INFO_FOREACH(cii, ci) {
132 0 : struct schedstate_percpu *spc = &ci->ci_schedstate;
133 :
134 0 : if (nrun_cpu[CPU_INFO_UNIT(ci)] == 0)
135 0 : continue;
136 0 : spc->spc_ldavg = (cexp[0] * spc->spc_ldavg +
137 0 : nrun_cpu[CPU_INFO_UNIT(ci)] * FSCALE *
138 0 : (FSCALE - cexp[0])) >> FSHIFT;
139 0 : }
140 0 : }
141 :
142 : /*
143 : * uvm_sysctl: sysctl hook into UVM system.
144 : */
145 : int
146 0 : uvm_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
147 : size_t newlen, struct proc *p)
148 : {
149 0 : struct process *pr = p->p_p;
150 0 : struct vmtotal vmtotals;
151 0 : int rv, t;
152 :
153 0 : switch (name[0]) {
154 : case VM_SWAPENCRYPT:
155 : #ifdef UVM_SWAP_ENCRYPT
156 0 : 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 0 : if (namelen != 1)
164 0 : return (ENOTDIR); /* overloaded */
165 : break;
166 : }
167 :
168 0 : switch (name[0]) {
169 : case VM_LOADAVG:
170 0 : return (sysctl_rdstruct(oldp, oldlenp, newp, &averunnable,
171 : sizeof(averunnable)));
172 :
173 : case VM_METER:
174 0 : uvm_total(&vmtotals);
175 0 : return (sysctl_rdstruct(oldp, oldlenp, newp, &vmtotals,
176 : sizeof(vmtotals)));
177 :
178 : case VM_UVMEXP:
179 0 : return (sysctl_rdstruct(oldp, oldlenp, newp, &uvmexp,
180 : sizeof(uvmexp)));
181 :
182 : case VM_NKMEMPAGES:
183 0 : return (sysctl_rdint(oldp, oldlenp, newp, nkmempages));
184 :
185 : case VM_PSSTRINGS:
186 0 : return (sysctl_rdstruct(oldp, oldlenp, newp, &pr->ps_strings,
187 : sizeof(pr->ps_strings)));
188 :
189 : case VM_ANONMIN:
190 0 : t = uvmexp.anonminpct;
191 0 : rv = sysctl_int(oldp, oldlenp, newp, newlen, &t);
192 0 : if (rv) {
193 0 : return rv;
194 : }
195 0 : if (t + uvmexp.vtextminpct + uvmexp.vnodeminpct > 95 || t < 0) {
196 0 : return EINVAL;
197 : }
198 0 : uvmexp.anonminpct = t;
199 0 : uvmexp.anonmin = t * 256 / 100;
200 0 : return rv;
201 :
202 : case VM_VTEXTMIN:
203 0 : t = uvmexp.vtextminpct;
204 0 : rv = sysctl_int(oldp, oldlenp, newp, newlen, &t);
205 0 : if (rv) {
206 0 : return rv;
207 : }
208 0 : if (uvmexp.anonminpct + t + uvmexp.vnodeminpct > 95 || t < 0) {
209 0 : return EINVAL;
210 : }
211 0 : uvmexp.vtextminpct = t;
212 0 : uvmexp.vtextmin = t * 256 / 100;
213 0 : return rv;
214 :
215 : case VM_VNODEMIN:
216 0 : t = uvmexp.vnodeminpct;
217 0 : rv = sysctl_int(oldp, oldlenp, newp, newlen, &t);
218 0 : if (rv) {
219 0 : return rv;
220 : }
221 0 : if (uvmexp.anonminpct + uvmexp.vtextminpct + t > 95 || t < 0) {
222 0 : return EINVAL;
223 : }
224 0 : uvmexp.vnodeminpct = t;
225 0 : uvmexp.vnodemin = t * 256 / 100;
226 0 : return rv;
227 :
228 : case VM_MAXSLP:
229 0 : return (sysctl_rdint(oldp, oldlenp, newp, maxslp));
230 :
231 : case VM_USPACE:
232 0 : return (sysctl_rdint(oldp, oldlenp, newp, USPACE));
233 :
234 : default:
235 0 : return (EOPNOTSUPP);
236 : }
237 : /* NOTREACHED */
238 0 : }
239 :
240 : /*
241 : * uvm_total: calculate the current state of the system.
242 : */
243 : void
244 0 : 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 0 : memset(totalp, 0, sizeof *totalp);
254 :
255 : /* calculate process statistics */
256 0 : LIST_FOREACH(p, &allproc, p_list) {
257 0 : switch (p->p_stat) {
258 : case 0:
259 : continue;
260 :
261 : case SSLEEP:
262 : case SSTOP:
263 0 : totalp->t_sl++;
264 0 : break;
265 : case SRUN:
266 : case SONPROC:
267 0 : if (p == p->p_cpu->ci_schedstate.spc_idleproc)
268 : continue;
269 : case SIDL:
270 0 : totalp->t_rq++;
271 0 : if (p->p_stat == SIDL)
272 : continue;
273 : break;
274 : }
275 : /*
276 : * note active objects
277 : */
278 : #if 0
279 : /*
280 : * XXXCDC: BOGUS! rethink this. in the mean time
281 : * don't do it.
282 : */
283 : paging = 0;
284 : vm_map_lock(map);
285 : for (map = &p->p_vmspace->vm_map, entry = map->header.next;
286 : entry != &map->header; entry = entry->next) {
287 : if (entry->is_a_map || entry->is_sub_map ||
288 : entry->object.uvm_obj == NULL)
289 : continue;
290 : /* XXX how to do this with uvm */
291 : }
292 : vm_map_unlock(map);
293 : if (paging)
294 : totalp->t_pw++;
295 : #endif
296 : }
297 : /*
298 : * Calculate object memory usage statistics.
299 : */
300 0 : totalp->t_free = uvmexp.free;
301 0 : totalp->t_vm = uvmexp.npages - uvmexp.free + uvmexp.swpginuse;
302 0 : totalp->t_avm = uvmexp.active + uvmexp.swpginuse; /* XXX */
303 0 : totalp->t_rm = uvmexp.npages - uvmexp.free;
304 0 : totalp->t_arm = uvmexp.active;
305 0 : totalp->t_vmshr = 0; /* XXX */
306 0 : totalp->t_avmshr = 0; /* XXX */
307 0 : totalp->t_rmshr = 0; /* XXX */
308 0 : totalp->t_armshr = 0; /* XXX */
309 0 : }
|