Annotation of src/sys/uvm/uvm_pdpolicy_clock.c, Revision 1.13
1.13 ! chuck 1: /* $NetBSD: uvm_pdpolicy_clock.c,v 1.12 2008/06/04 12:41:40 ad Exp $ */
1.2 yamt 2: /* NetBSD: uvm_pdaemon.c,v 1.72 2006/01/05 10:47:33 yamt Exp $ */
3:
4: /*
5: * Copyright (c) 1997 Charles D. Cranor and Washington University.
6: * Copyright (c) 1991, 1993, The Regents of the University of California.
7: *
8: * All rights reserved.
9: *
10: * This code is derived from software contributed to Berkeley by
11: * The Mach Operating System project at Carnegie-Mellon University.
12: *
13: * Redistribution and use in source and binary forms, with or without
14: * modification, are permitted provided that the following conditions
15: * are met:
16: * 1. Redistributions of source code must retain the above copyright
17: * notice, this list of conditions and the following disclaimer.
18: * 2. Redistributions in binary form must reproduce the above copyright
19: * notice, this list of conditions and the following disclaimer in the
20: * documentation and/or other materials provided with the distribution.
1.13 ! chuck 21: * 3. Neither the name of the University nor the names of its contributors
1.2 yamt 22: * may be used to endorse or promote products derived from this software
23: * without specific prior written permission.
24: *
25: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35: * SUCH DAMAGE.
36: *
37: * @(#)vm_pageout.c 8.5 (Berkeley) 2/14/94
38: * from: Id: uvm_pdaemon.c,v 1.1.2.32 1998/02/06 05:26:30 chs Exp
39: *
40: *
41: * Copyright (c) 1987, 1990 Carnegie-Mellon University.
42: * All rights reserved.
43: *
44: * Permission to use, copy, modify and distribute this software and
45: * its documentation is hereby granted, provided that both the copyright
46: * notice and this permission notice appear in all copies of the
47: * software, derivative works or modified versions, and any portions
48: * thereof, and that both notices appear in supporting documentation.
49: *
50: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
51: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
52: * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
53: *
54: * Carnegie Mellon requests users of this software to return to
55: *
56: * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
57: * School of Computer Science
58: * Carnegie Mellon University
59: * Pittsburgh PA 15213-3890
60: *
61: * any improvements or extensions that they make and grant Carnegie the
62: * rights to redistribute these changes.
63: */
64:
65: #if defined(PDSIM)
66:
67: #include "pdsim.h"
68:
69: #else /* defined(PDSIM) */
70:
71: #include <sys/cdefs.h>
1.13 ! chuck 72: __KERNEL_RCSID(0, "$NetBSD: uvm_pdpolicy_clock.c,v 1.12 2008/06/04 12:41:40 ad Exp $");
1.2 yamt 73:
74: #include <sys/param.h>
75: #include <sys/proc.h>
76: #include <sys/systm.h>
77: #include <sys/kernel.h>
78:
79: #include <uvm/uvm.h>
80: #include <uvm/uvm_pdpolicy.h>
81: #include <uvm/uvm_pdpolicy_impl.h>
82:
83: #endif /* defined(PDSIM) */
84:
85: #define PQ_INACTIVE PQ_PRIVATE1 /* page is in inactive list */
86: #define PQ_ACTIVE PQ_PRIVATE2 /* page is in active list */
87:
88: #if !defined(CLOCK_INACTIVEPCT)
89: #define CLOCK_INACTIVEPCT 33
90: #endif /* !defined(CLOCK_INACTIVEPCT) */
91:
92: struct uvmpdpol_globalstate {
93: struct pglist s_activeq; /* allocated pages, in use */
94: struct pglist s_inactiveq; /* pages between the clock hands */
95: int s_active;
96: int s_inactive;
97: int s_inactarg;
98: struct uvm_pctparam s_anonmin;
99: struct uvm_pctparam s_filemin;
100: struct uvm_pctparam s_execmin;
101: struct uvm_pctparam s_anonmax;
102: struct uvm_pctparam s_filemax;
103: struct uvm_pctparam s_execmax;
104: struct uvm_pctparam s_inactivepct;
105: };
106:
107: struct uvmpdpol_scanstate {
1.7 thorpej 108: bool ss_first;
109: bool ss_anonreact, ss_filereact, ss_execreact;
1.2 yamt 110: struct vm_page *ss_nextpg;
111: };
112:
113: static struct uvmpdpol_globalstate pdpol_state;
114: static struct uvmpdpol_scanstate pdpol_scanstate;
115:
116: PDPOL_EVCNT_DEFINE(reactexec)
117: PDPOL_EVCNT_DEFINE(reactfile)
118: PDPOL_EVCNT_DEFINE(reactanon)
119:
120: static void
121: clock_tune(void)
122: {
123: struct uvmpdpol_globalstate *s = &pdpol_state;
124:
125: s->s_inactarg = UVM_PCTPARAM_APPLY(&s->s_inactivepct,
126: s->s_active + s->s_inactive);
127: if (s->s_inactarg <= uvmexp.freetarg) {
128: s->s_inactarg = uvmexp.freetarg + 1;
129: }
130: }
131:
132: void
133: uvmpdpol_scaninit(void)
134: {
135: struct uvmpdpol_globalstate *s = &pdpol_state;
136: struct uvmpdpol_scanstate *ss = &pdpol_scanstate;
137: int t;
1.7 thorpej 138: bool anonunder, fileunder, execunder;
139: bool anonover, fileover, execover;
140: bool anonreact, filereact, execreact;
1.2 yamt 141:
142: /*
143: * decide which types of pages we want to reactivate instead of freeing
144: * to keep usage within the minimum and maximum usage limits.
145: */
146:
147: t = s->s_active + s->s_inactive + uvmexp.free;
148: anonunder = uvmexp.anonpages <= UVM_PCTPARAM_APPLY(&s->s_anonmin, t);
149: fileunder = uvmexp.filepages <= UVM_PCTPARAM_APPLY(&s->s_filemin, t);
150: execunder = uvmexp.execpages <= UVM_PCTPARAM_APPLY(&s->s_execmin, t);
151: anonover = uvmexp.anonpages > UVM_PCTPARAM_APPLY(&s->s_anonmax, t);
152: fileover = uvmexp.filepages > UVM_PCTPARAM_APPLY(&s->s_filemax, t);
153: execover = uvmexp.execpages > UVM_PCTPARAM_APPLY(&s->s_execmax, t);
154: anonreact = anonunder || (!anonover && (fileover || execover));
155: filereact = fileunder || (!fileover && (anonover || execover));
156: execreact = execunder || (!execover && (anonover || fileover));
157: if (filereact && execreact && (anonreact || uvm_swapisfull())) {
1.8 thorpej 158: anonreact = filereact = execreact = false;
1.2 yamt 159: }
160: ss->ss_anonreact = anonreact;
161: ss->ss_filereact = filereact;
162: ss->ss_execreact = execreact;
163:
1.8 thorpej 164: ss->ss_first = true;
1.2 yamt 165: }
166:
167: struct vm_page *
168: uvmpdpol_selectvictim(void)
169: {
170: struct uvmpdpol_scanstate *ss = &pdpol_scanstate;
171: struct vm_page *pg;
172:
1.9 ad 173: KASSERT(mutex_owned(&uvm_pageqlock));
1.2 yamt 174:
175: while (/* CONSTCOND */ 1) {
176: struct vm_anon *anon;
177: struct uvm_object *uobj;
178:
179: if (ss->ss_first) {
180: pg = TAILQ_FIRST(&pdpol_state.s_inactiveq);
1.8 thorpej 181: ss->ss_first = false;
1.2 yamt 182: } else {
183: pg = ss->ss_nextpg;
184: if (pg != NULL && (pg->pqflags & PQ_INACTIVE) == 0) {
185: pg = TAILQ_FIRST(&pdpol_state.s_inactiveq);
186: }
187: }
188: if (pg == NULL) {
189: break;
190: }
1.12 ad 191: ss->ss_nextpg = TAILQ_NEXT(pg, pageq.queue);
1.2 yamt 192:
193: uvmexp.pdscans++;
194:
195: /*
196: * move referenced pages back to active queue and
197: * skip to next page.
198: */
199:
200: if (pmap_is_referenced(pg)) {
201: uvmpdpol_pageactivate(pg);
202: uvmexp.pdreact++;
203: continue;
204: }
205:
206: anon = pg->uanon;
207: uobj = pg->uobject;
208:
209: /*
210: * enforce the minimum thresholds on different
211: * types of memory usage. if reusing the current
212: * page would reduce that type of usage below its
213: * minimum, reactivate the page instead and move
214: * on to the next page.
215: */
216:
217: if (uobj && UVM_OBJ_IS_VTEXT(uobj) && ss->ss_execreact) {
218: uvmpdpol_pageactivate(pg);
219: PDPOL_EVCNT_INCR(reactexec);
220: continue;
221: }
222: if (uobj && UVM_OBJ_IS_VNODE(uobj) &&
223: !UVM_OBJ_IS_VTEXT(uobj) && ss->ss_filereact) {
224: uvmpdpol_pageactivate(pg);
225: PDPOL_EVCNT_INCR(reactfile);
226: continue;
227: }
228: if ((anon || UVM_OBJ_IS_AOBJ(uobj)) && ss->ss_anonreact) {
229: uvmpdpol_pageactivate(pg);
230: PDPOL_EVCNT_INCR(reactanon);
231: continue;
232: }
233:
234: break;
235: }
236:
237: return pg;
238: }
239:
240: void
241: uvmpdpol_balancequeue(int swap_shortage)
242: {
243: int inactive_shortage;
244: struct vm_page *p, *nextpg;
245:
246: /*
247: * we have done the scan to get free pages. now we work on meeting
248: * our inactive target.
249: */
250:
251: inactive_shortage = pdpol_state.s_inactarg - pdpol_state.s_inactive;
252: for (p = TAILQ_FIRST(&pdpol_state.s_activeq);
253: p != NULL && (inactive_shortage > 0 || swap_shortage > 0);
254: p = nextpg) {
1.12 ad 255: nextpg = TAILQ_NEXT(p, pageq.queue);
1.2 yamt 256:
257: /*
258: * if there's a shortage of swap slots, try to free it.
259: */
260:
261: if (swap_shortage > 0 && (p->pqflags & PQ_SWAPBACKED) != 0) {
262: if (uvmpd_trydropswap(p)) {
263: swap_shortage--;
264: }
265: }
266:
267: /*
268: * if there's a shortage of inactive pages, deactivate.
269: */
270:
271: if (inactive_shortage > 0) {
272: /* no need to check wire_count as pg is "active" */
273: uvmpdpol_pagedeactivate(p);
274: uvmexp.pddeact++;
275: inactive_shortage--;
276: }
277: }
278: }
279:
280: void
281: uvmpdpol_pagedeactivate(struct vm_page *pg)
282: {
283:
1.9 ad 284: KASSERT(mutex_owned(&uvm_pageqlock));
1.2 yamt 285: if (pg->pqflags & PQ_ACTIVE) {
1.12 ad 286: TAILQ_REMOVE(&pdpol_state.s_activeq, pg, pageq.queue);
1.2 yamt 287: pg->pqflags &= ~PQ_ACTIVE;
288: KASSERT(pdpol_state.s_active > 0);
289: pdpol_state.s_active--;
290: }
291: if ((pg->pqflags & PQ_INACTIVE) == 0) {
292: KASSERT(pg->wire_count == 0);
1.10 yamt 293: pmap_clear_reference(pg);
1.12 ad 294: TAILQ_INSERT_TAIL(&pdpol_state.s_inactiveq, pg, pageq.queue);
1.2 yamt 295: pg->pqflags |= PQ_INACTIVE;
296: pdpol_state.s_inactive++;
297: }
298: }
299:
300: void
301: uvmpdpol_pageactivate(struct vm_page *pg)
302: {
303:
304: uvmpdpol_pagedequeue(pg);
1.12 ad 305: TAILQ_INSERT_TAIL(&pdpol_state.s_activeq, pg, pageq.queue);
1.2 yamt 306: pg->pqflags |= PQ_ACTIVE;
307: pdpol_state.s_active++;
308: }
309:
310: void
311: uvmpdpol_pagedequeue(struct vm_page *pg)
312: {
313:
314: if (pg->pqflags & PQ_ACTIVE) {
1.9 ad 315: KASSERT(mutex_owned(&uvm_pageqlock));
1.12 ad 316: TAILQ_REMOVE(&pdpol_state.s_activeq, pg, pageq.queue);
1.2 yamt 317: pg->pqflags &= ~PQ_ACTIVE;
318: KASSERT(pdpol_state.s_active > 0);
319: pdpol_state.s_active--;
320: } else if (pg->pqflags & PQ_INACTIVE) {
1.9 ad 321: KASSERT(mutex_owned(&uvm_pageqlock));
1.12 ad 322: TAILQ_REMOVE(&pdpol_state.s_inactiveq, pg, pageq.queue);
1.2 yamt 323: pg->pqflags &= ~PQ_INACTIVE;
324: KASSERT(pdpol_state.s_inactive > 0);
325: pdpol_state.s_inactive--;
326: }
327: }
328:
329: void
330: uvmpdpol_pageenqueue(struct vm_page *pg)
331: {
332:
333: uvmpdpol_pageactivate(pg);
334: }
335:
336: void
1.5 yamt 337: uvmpdpol_anfree(struct vm_anon *an)
1.2 yamt 338: {
339: }
340:
1.7 thorpej 341: bool
1.2 yamt 342: uvmpdpol_pageisqueued_p(struct vm_page *pg)
343: {
344:
345: return (pg->pqflags & (PQ_ACTIVE | PQ_INACTIVE)) != 0;
346: }
347:
348: void
349: uvmpdpol_estimatepageable(int *active, int *inactive)
350: {
351:
352: if (active) {
353: *active = pdpol_state.s_active;
354: }
355: if (inactive) {
356: *inactive = pdpol_state.s_inactive;
357: }
358: }
359:
360: #if !defined(PDSIM)
361: static int
362: min_check(struct uvm_pctparam *pct, int t)
363: {
364: struct uvmpdpol_globalstate *s = &pdpol_state;
365: int total = t;
366:
367: if (pct != &s->s_anonmin) {
368: total += uvm_pctparam_get(&s->s_anonmin);
369: }
370: if (pct != &s->s_filemin) {
371: total += uvm_pctparam_get(&s->s_filemin);
372: }
373: if (pct != &s->s_execmin) {
374: total += uvm_pctparam_get(&s->s_execmin);
375: }
376: if (total > 95) {
377: return EINVAL;
378: }
379: return 0;
380: }
381: #endif /* !defined(PDSIM) */
382:
383: void
384: uvmpdpol_init(void)
385: {
386: struct uvmpdpol_globalstate *s = &pdpol_state;
387:
388: TAILQ_INIT(&s->s_activeq);
389: TAILQ_INIT(&s->s_inactiveq);
390: uvm_pctparam_init(&s->s_inactivepct, CLOCK_INACTIVEPCT, NULL);
391: uvm_pctparam_init(&s->s_anonmin, 10, min_check);
392: uvm_pctparam_init(&s->s_filemin, 10, min_check);
393: uvm_pctparam_init(&s->s_execmin, 5, min_check);
394: uvm_pctparam_init(&s->s_anonmax, 80, NULL);
395: uvm_pctparam_init(&s->s_filemax, 50, NULL);
396: uvm_pctparam_init(&s->s_execmax, 30, NULL);
397: }
398:
399: void
400: uvmpdpol_reinit(void)
401: {
402: }
403:
1.7 thorpej 404: bool
1.2 yamt 405: uvmpdpol_needsscan_p(void)
406: {
407:
408: return pdpol_state.s_inactive < pdpol_state.s_inactarg;
409: }
410:
411: void
412: uvmpdpol_tune(void)
413: {
414:
415: clock_tune();
416: }
417:
418: #if !defined(PDSIM)
419:
420: #include <sys/sysctl.h> /* XXX SYSCTL_DESCR */
421:
422: void
423: uvmpdpol_sysctlsetup(void)
424: {
425: struct uvmpdpol_globalstate *s = &pdpol_state;
426:
427: uvm_pctparam_createsysctlnode(&s->s_anonmin, "anonmin",
428: SYSCTL_DESCR("Percentage of physical memory reserved "
429: "for anonymous application data"));
430: uvm_pctparam_createsysctlnode(&s->s_filemin, "filemin",
431: SYSCTL_DESCR("Percentage of physical memory reserved "
1.11 martin 432: "for cached file data"));
1.2 yamt 433: uvm_pctparam_createsysctlnode(&s->s_execmin, "execmin",
434: SYSCTL_DESCR("Percentage of physical memory reserved "
1.11 martin 435: "for cached executable data"));
1.2 yamt 436:
437: uvm_pctparam_createsysctlnode(&s->s_anonmax, "anonmax",
438: SYSCTL_DESCR("Percentage of physical memory which will "
439: "be reclaimed from other usage for "
440: "anonymous application data"));
441: uvm_pctparam_createsysctlnode(&s->s_filemax, "filemax",
442: SYSCTL_DESCR("Percentage of physical memory which will "
443: "be reclaimed from other usage for cached "
444: "file data"));
445: uvm_pctparam_createsysctlnode(&s->s_execmax, "execmax",
446: SYSCTL_DESCR("Percentage of physical memory which will "
447: "be reclaimed from other usage for cached "
448: "executable data"));
449:
450: uvm_pctparam_createsysctlnode(&s->s_inactivepct, "inactivepct",
451: SYSCTL_DESCR("Percentage of inactive queue of "
452: "the entire (active + inactive) queue"));
453: }
454:
455: #endif /* !defined(PDSIM) */
456:
457: #if defined(PDSIM)
458: void
459: pdsim_dump(const char *id)
460: {
461: #if defined(DEBUG)
462: /* XXX */
463: #endif /* defined(DEBUG) */
464: }
465: #endif /* defined(PDSIM) */
CVSweb <webmaster@jp.NetBSD.org>