xref: /netbsd-src/sys/uvm/uvm_meter.c (revision aaf4ece63a859a04e37cf3a7229b5fab0157cc06)
1 /*	$NetBSD: uvm_meter.c,v 1.39 2005/12/21 12:23:44 yamt 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.39 2005/12/21 12:23:44 yamt 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  * sysctl helper routine for uvm_pctparam.
304  */
305 static int
306 sysctl_uvmpctparam(SYSCTLFN_ARGS)
307 {
308 	int t, error;
309 	struct sysctlnode node;
310 	struct uvm_pctparam *pct;
311 
312 	pct = rnode->sysctl_data;
313 	t = pct->pct_pct;
314 
315 	node = *rnode;
316 	node.sysctl_data = &t;
317 	t = *(int*)rnode->sysctl_data;
318 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
319 	if (error || newp == NULL)
320 		return error;
321 
322 	if (t < 0 || t > 100)
323 		return EINVAL;
324 
325 	uvm_pctparam_set(pct, t);
326 
327 	return (0);
328 }
329 
330 /*
331  * uvm_sysctl: sysctl hook into UVM system.
332  */
333 SYSCTL_SETUP(sysctl_vm_setup, "sysctl vm subtree setup")
334 {
335 
336 	sysctl_createv(clog, 0, NULL, NULL,
337 		       CTLFLAG_PERMANENT,
338 		       CTLTYPE_NODE, "vm", NULL,
339 		       NULL, 0, NULL, 0,
340 		       CTL_VM, CTL_EOL);
341 	sysctl_createv(clog, 0, NULL, NULL,
342 		       CTLFLAG_PERMANENT,
343 		       CTLTYPE_STRUCT, "vmmeter",
344 		       SYSCTL_DESCR("Simple system-wide virtual memory "
345 				    "statistics"),
346 		       sysctl_vm_meter, 0, NULL, sizeof(struct vmtotal),
347 		       CTL_VM, VM_METER, CTL_EOL);
348 	sysctl_createv(clog, 0, NULL, NULL,
349 		       CTLFLAG_PERMANENT,
350 		       CTLTYPE_STRUCT, "loadavg",
351 		       SYSCTL_DESCR("System load average history"),
352 		       NULL, 0, &averunnable, sizeof(averunnable),
353 		       CTL_VM, VM_LOADAVG, CTL_EOL);
354 	sysctl_createv(clog, 0, NULL, NULL,
355 		       CTLFLAG_PERMANENT,
356 		       CTLTYPE_STRUCT, "uvmexp",
357 		       SYSCTL_DESCR("Detailed system-wide virtual memory "
358 				    "statistics"),
359 		       sysctl_vm_uvmexp, 0, &uvmexp, sizeof(uvmexp),
360 		       CTL_VM, VM_UVMEXP, CTL_EOL);
361 	sysctl_createv(clog, 0, NULL, NULL,
362 		       CTLFLAG_PERMANENT,
363 		       CTLTYPE_INT, "nkmempages",
364 		       SYSCTL_DESCR("Default number of pages in kmem_map"),
365 		       NULL, 0, &nkmempages, 0,
366 		       CTL_VM, VM_NKMEMPAGES, CTL_EOL);
367 	sysctl_createv(clog, 0, NULL, NULL,
368 		       CTLFLAG_PERMANENT,
369 		       CTLTYPE_STRUCT, "uvmexp2",
370 		       SYSCTL_DESCR("Detailed system-wide virtual memory "
371 				    "statistics (MI)"),
372 		       sysctl_vm_uvmexp2, 0, NULL, 0,
373 		       CTL_VM, VM_UVMEXP2, CTL_EOL);
374 	sysctl_createv(clog, 0, NULL, NULL,
375 		       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
376 		       CTLTYPE_INT, "anonmin",
377 		       SYSCTL_DESCR("Percentage of physical memory reserved "
378 				    "for anonymous application data"),
379 		       sysctl_vm_updateminmax, 0, &uvmexp.anonminpct, 0,
380 		       CTL_VM, VM_ANONMIN, CTL_EOL);
381 	sysctl_createv(clog, 0, NULL, NULL,
382 		       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
383 		       CTLTYPE_INT, "execmin",
384 		       SYSCTL_DESCR("Percentage of physical memory reserved "
385 				    "for cached executable data"),
386 		       sysctl_vm_updateminmax, 0, &uvmexp.execminpct, 0,
387 		       CTL_VM, VM_EXECMIN, CTL_EOL);
388 	sysctl_createv(clog, 0, NULL, NULL,
389 		       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
390 		       CTLTYPE_INT, "filemin",
391 		       SYSCTL_DESCR("Percentage of physical memory reserved "
392 				    "for cached file data"),
393 		       sysctl_vm_updateminmax, 0, &uvmexp.fileminpct, 0,
394 		       CTL_VM, VM_FILEMIN, CTL_EOL);
395 	sysctl_createv(clog, 0, NULL, NULL,
396 		       CTLFLAG_PERMANENT, CTLTYPE_INT, "maxslp",
397 		       SYSCTL_DESCR("Maximum process sleep time before being "
398 				    "swapped"),
399 		       NULL, 0, &maxslp, 0,
400 		       CTL_VM, VM_MAXSLP, CTL_EOL);
401 	sysctl_createv(clog, 0, NULL, NULL,
402 		       CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE,
403 		       CTLTYPE_INT, "uspace",
404 		       SYSCTL_DESCR("Number of bytes allocated for a kernel "
405 				    "stack"),
406 		       NULL, USPACE, NULL, 0,
407 		       CTL_VM, VM_USPACE, CTL_EOL);
408 	sysctl_createv(clog, 0, NULL, NULL,
409 		       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
410 		       CTLTYPE_INT, "anonmax",
411 		       SYSCTL_DESCR("Percentage of physical memory which will "
412 				    "be reclaimed from other usage for "
413 				    "anonymous application data"),
414 		       sysctl_vm_updateminmax, 0, &uvmexp.anonmaxpct, 0,
415 		       CTL_VM, VM_ANONMAX, CTL_EOL);
416 	sysctl_createv(clog, 0, NULL, NULL,
417 		       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
418 		       CTLTYPE_INT, "execmax",
419                        SYSCTL_DESCR("Percentage of physical memory which will "
420 				    "be reclaimed from other usage for cached "
421 				    "executable data"),
422 		       sysctl_vm_updateminmax, 0, &uvmexp.execmaxpct, 0,
423 		       CTL_VM, VM_EXECMAX, CTL_EOL);
424 	sysctl_createv(clog, 0, NULL, NULL,
425 		       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
426 		       CTLTYPE_INT, "filemax",
427 		       SYSCTL_DESCR("Percentage of physical memory which will "
428 				    "be reclaimed from other usage for cached "
429 				    "file data"),
430 		       sysctl_vm_updateminmax, 0, &uvmexp.filemaxpct, 0,
431 		       CTL_VM, VM_FILEMAX, CTL_EOL);
432 	sysctl_createv(clog, 0, NULL, NULL,
433 		       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
434 		       CTLTYPE_INT, "idlezero",
435 		       SYSCTL_DESCR("Whether try to zero pages in idle loop"),
436 		       NULL, 0, &vm_page_zero_enable, 0,
437 		       CTL_VM, CTL_CREATE, CTL_EOL);
438 	sysctl_createv(clog, 0, NULL, NULL,
439 		       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
440 		       CTLTYPE_INT, "inactivepct",
441 		       SYSCTL_DESCR("Percentage of inactive queue of "
442 				    "the entire (active + inactive) queue"),
443 		       sysctl_uvmpctparam, 0, &uvmexp.inactivepct, 0,
444 		       CTL_VM, CTL_CREATE, CTL_EOL);
445 }
446 
447 /*
448  * uvm_total: calculate the current state of the system.
449  */
450 static void
451 uvm_total(struct vmtotal *totalp)
452 {
453 	struct lwp *l;
454 #if 0
455 	struct vm_map_entry *	entry;
456 	struct vm_map *map;
457 	int paging;
458 #endif
459 
460 	memset(totalp, 0, sizeof *totalp);
461 
462 	/*
463 	 * calculate process statistics
464 	 */
465 
466 	proclist_lock_read();
467 	    LIST_FOREACH(l, &alllwp, l_list) {
468 		if (l->l_proc->p_flag & P_SYSTEM)
469 			continue;
470 		switch (l->l_stat) {
471 		case 0:
472 			continue;
473 
474 		case LSSLEEP:
475 		case LSSTOP:
476 			if (l->l_flag & L_INMEM) {
477 				if (l->l_priority <= PZERO)
478 					totalp->t_dw++;
479 				else if (l->l_slptime < maxslp)
480 					totalp->t_sl++;
481 			} else if (l->l_slptime < maxslp)
482 				totalp->t_sw++;
483 			if (l->l_slptime >= maxslp)
484 				continue;
485 			break;
486 
487 		case LSRUN:
488 		case LSONPROC:
489 		case LSIDL:
490 			if (l->l_flag & L_INMEM)
491 				totalp->t_rq++;
492 			else
493 				totalp->t_sw++;
494 			if (l->l_stat == LSIDL)
495 				continue;
496 			break;
497 		}
498 		/*
499 		 * note active objects
500 		 */
501 #if 0
502 		/*
503 		 * XXXCDC: BOGUS!  rethink this.  in the mean time
504 		 * don't do it.
505 		 */
506 		paging = 0;
507 		vm_map_lock(map);
508 		for (map = &p->p_vmspace->vm_map, entry = map->header.next;
509 		    entry != &map->header; entry = entry->next) {
510 			if (entry->is_a_map || entry->is_sub_map ||
511 			    entry->object.uvm_obj == NULL)
512 				continue;
513 			/* XXX how to do this with uvm */
514 		}
515 		vm_map_unlock(map);
516 		if (paging)
517 			totalp->t_pw++;
518 #endif
519 	}
520 	proclist_unlock_read();
521 	/*
522 	 * Calculate object memory usage statistics.
523 	 */
524 	totalp->t_free = uvmexp.free;
525 	totalp->t_vm = uvmexp.npages - uvmexp.free + uvmexp.swpginuse;
526 	totalp->t_avm = uvmexp.active + uvmexp.swpginuse;	/* XXX */
527 	totalp->t_rm = uvmexp.npages - uvmexp.free;
528 	totalp->t_arm = uvmexp.active;
529 	totalp->t_vmshr = 0;		/* XXX */
530 	totalp->t_avmshr = 0;		/* XXX */
531 	totalp->t_rmshr = 0;		/* XXX */
532 	totalp->t_armshr = 0;		/* XXX */
533 }
534 
535 void
536 uvm_pctparam_set(struct uvm_pctparam *pct, int val)
537 {
538 
539 	pct->pct_pct = val;
540 	pct->pct_scaled = val * UVM_PCTPARAM_SCALE / 100;
541 }
542