1 /* $NetBSD: uvm_pdpolicy_clock.c,v 1.11 2008/03/07 08:44:51 martin Exp $ */
2 /* NetBSD: uvm_pdaemon.c,v 1.72 2006/01/05 10:47:33 yamt Exp $ */
5 * Copyright (c) 1997 Charles D. Cranor and Washington University.
6 * Copyright (c) 1991, 1993, The Regents of the University of California.
10 * This code is derived from software contributed to Berkeley by
11 * The Mach Operating System project at Carnegie-Mellon University.
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
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.
21 * 3. All advertising materials mentioning features or use of this software
22 * must display the following acknowledgement:
23 * This product includes software developed by Charles D. Cranor,
24 * Washington University, the University of California, Berkeley and
26 * 4. Neither the name of the University nor the names of its contributors
27 * may be used to endorse or promote products derived from this software
28 * without specific prior written permission.
30 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
31 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
34 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42 * @(#)vm_pageout.c 8.5 (Berkeley) 2/14/94
43 * from: Id: uvm_pdaemon.c,v 1.1.2.32 1998/02/06 05:26:30 chs Exp
46 * Copyright (c) 1987, 1990 Carnegie-Mellon University.
47 * All rights reserved.
49 * Permission to use, copy, modify and distribute this software and
50 * its documentation is hereby granted, provided that both the copyright
51 * notice and this permission notice appear in all copies of the
52 * software, derivative works or modified versions, and any portions
53 * thereof, and that both notices appear in supporting documentation.
55 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
56 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
57 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
59 * Carnegie Mellon requests users of this software to return to
61 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
62 * School of Computer Science
63 * Carnegie Mellon University
64 * Pittsburgh PA 15213-3890
66 * any improvements or extensions that they make and grant Carnegie the
67 * rights to redistribute these changes.
74 #else /* defined(PDSIM) */
76 #include <sys/cdefs.h>
77 __KERNEL_RCSID(0, "$NetBSD: uvm_pdpolicy_clock.c,v 1.11 2008/03/07 08:44:51 martin Exp $");
79 #include <sys/param.h>
81 #include <sys/systm.h>
82 #include <sys/kernel.h>
85 #include <uvm/uvm_pdpolicy.h>
86 #include <uvm/uvm_pdpolicy_impl.h>
88 #endif /* defined(PDSIM) */
90 #define PQ_INACTIVE PQ_PRIVATE1 /* page is in inactive list */
91 #define PQ_ACTIVE PQ_PRIVATE2 /* page is in active list */
93 #if !defined(CLOCK_INACTIVEPCT)
94 #define CLOCK_INACTIVEPCT 33
95 #endif /* !defined(CLOCK_INACTIVEPCT) */
97 struct uvmpdpol_globalstate
{
98 struct pglist s_activeq
; /* allocated pages, in use */
99 struct pglist s_inactiveq
; /* pages between the clock hands */
103 struct uvm_pctparam s_anonmin
;
104 struct uvm_pctparam s_filemin
;
105 struct uvm_pctparam s_execmin
;
106 struct uvm_pctparam s_anonmax
;
107 struct uvm_pctparam s_filemax
;
108 struct uvm_pctparam s_execmax
;
109 struct uvm_pctparam s_inactivepct
;
112 struct uvmpdpol_scanstate
{
114 bool ss_anonreact
, ss_filereact
, ss_execreact
;
115 struct vm_page
*ss_nextpg
;
118 static struct uvmpdpol_globalstate pdpol_state
;
119 static struct uvmpdpol_scanstate pdpol_scanstate
;
121 PDPOL_EVCNT_DEFINE(reactexec
)
122 PDPOL_EVCNT_DEFINE(reactfile
)
123 PDPOL_EVCNT_DEFINE(reactanon
)
128 struct uvmpdpol_globalstate
*s
= &pdpol_state
;
130 s
->s_inactarg
= UVM_PCTPARAM_APPLY(&s
->s_inactivepct
,
131 s
->s_active
+ s
->s_inactive
);
132 if (s
->s_inactarg
<= uvmexp
.freetarg
) {
133 s
->s_inactarg
= uvmexp
.freetarg
+ 1;
138 uvmpdpol_scaninit(void)
140 struct uvmpdpol_globalstate
*s
= &pdpol_state
;
141 struct uvmpdpol_scanstate
*ss
= &pdpol_scanstate
;
143 bool anonunder
, fileunder
, execunder
;
144 bool anonover
, fileover
, execover
;
145 bool anonreact
, filereact
, execreact
;
148 * decide which types of pages we want to reactivate instead of freeing
149 * to keep usage within the minimum and maximum usage limits.
152 t
= s
->s_active
+ s
->s_inactive
+ uvmexp
.free
;
153 anonunder
= uvmexp
.anonpages
<= UVM_PCTPARAM_APPLY(&s
->s_anonmin
, t
);
154 fileunder
= uvmexp
.filepages
<= UVM_PCTPARAM_APPLY(&s
->s_filemin
, t
);
155 execunder
= uvmexp
.execpages
<= UVM_PCTPARAM_APPLY(&s
->s_execmin
, t
);
156 anonover
= uvmexp
.anonpages
> UVM_PCTPARAM_APPLY(&s
->s_anonmax
, t
);
157 fileover
= uvmexp
.filepages
> UVM_PCTPARAM_APPLY(&s
->s_filemax
, t
);
158 execover
= uvmexp
.execpages
> UVM_PCTPARAM_APPLY(&s
->s_execmax
, t
);
159 anonreact
= anonunder
|| (!anonover
&& (fileover
|| execover
));
160 filereact
= fileunder
|| (!fileover
&& (anonover
|| execover
));
161 execreact
= execunder
|| (!execover
&& (anonover
|| fileover
));
162 if (filereact
&& execreact
&& (anonreact
|| uvm_swapisfull())) {
163 anonreact
= filereact
= execreact
= false;
165 ss
->ss_anonreact
= anonreact
;
166 ss
->ss_filereact
= filereact
;
167 ss
->ss_execreact
= execreact
;
173 uvmpdpol_selectvictim(void)
175 struct uvmpdpol_scanstate
*ss
= &pdpol_scanstate
;
178 KASSERT(mutex_owned(&uvm_pageqlock
));
180 while (/* CONSTCOND */ 1) {
181 struct vm_anon
*anon
;
182 struct uvm_object
*uobj
;
185 pg
= TAILQ_FIRST(&pdpol_state
.s_inactiveq
);
186 ss
->ss_first
= false;
189 if (pg
!= NULL
&& (pg
->pqflags
& PQ_INACTIVE
) == 0) {
190 pg
= TAILQ_FIRST(&pdpol_state
.s_inactiveq
);
196 ss
->ss_nextpg
= TAILQ_NEXT(pg
, pageq
.queue
);
201 * move referenced pages back to active queue and
205 if (pmap_is_referenced(pg
)) {
206 uvmpdpol_pageactivate(pg
);
215 * enforce the minimum thresholds on different
216 * types of memory usage. if reusing the current
217 * page would reduce that type of usage below its
218 * minimum, reactivate the page instead and move
219 * on to the next page.
222 if (uobj
&& UVM_OBJ_IS_VTEXT(uobj
) && ss
->ss_execreact
) {
223 uvmpdpol_pageactivate(pg
);
224 PDPOL_EVCNT_INCR(reactexec
);
227 if (uobj
&& UVM_OBJ_IS_VNODE(uobj
) &&
228 !UVM_OBJ_IS_VTEXT(uobj
) && ss
->ss_filereact
) {
229 uvmpdpol_pageactivate(pg
);
230 PDPOL_EVCNT_INCR(reactfile
);
233 if ((anon
|| UVM_OBJ_IS_AOBJ(uobj
)) && ss
->ss_anonreact
) {
234 uvmpdpol_pageactivate(pg
);
235 PDPOL_EVCNT_INCR(reactanon
);
246 uvmpdpol_balancequeue(int swap_shortage
)
248 int inactive_shortage
;
249 struct vm_page
*p
, *nextpg
;
252 * we have done the scan to get free pages. now we work on meeting
253 * our inactive target.
256 inactive_shortage
= pdpol_state
.s_inactarg
- pdpol_state
.s_inactive
;
257 for (p
= TAILQ_FIRST(&pdpol_state
.s_activeq
);
258 p
!= NULL
&& (inactive_shortage
> 0 || swap_shortage
> 0);
260 nextpg
= TAILQ_NEXT(p
, pageq
.queue
);
263 * if there's a shortage of swap slots, try to free it.
266 if (swap_shortage
> 0 && (p
->pqflags
& PQ_SWAPBACKED
) != 0) {
267 if (uvmpd_trydropswap(p
)) {
273 * if there's a shortage of inactive pages, deactivate.
276 if (inactive_shortage
> 0) {
277 /* no need to check wire_count as pg is "active" */
278 uvmpdpol_pagedeactivate(p
);
286 uvmpdpol_pagedeactivate(struct vm_page
*pg
)
289 KASSERT(mutex_owned(&uvm_pageqlock
));
290 if (pg
->pqflags
& PQ_ACTIVE
) {
291 TAILQ_REMOVE(&pdpol_state
.s_activeq
, pg
, pageq
.queue
);
292 pg
->pqflags
&= ~PQ_ACTIVE
;
293 KASSERT(pdpol_state
.s_active
> 0);
294 pdpol_state
.s_active
--;
296 if ((pg
->pqflags
& PQ_INACTIVE
) == 0) {
297 KASSERT(pg
->wire_count
== 0);
298 pmap_clear_reference(pg
);
299 TAILQ_INSERT_TAIL(&pdpol_state
.s_inactiveq
, pg
, pageq
.queue
);
300 pg
->pqflags
|= PQ_INACTIVE
;
301 pdpol_state
.s_inactive
++;
306 uvmpdpol_pageactivate(struct vm_page
*pg
)
309 uvmpdpol_pagedequeue(pg
);
310 TAILQ_INSERT_TAIL(&pdpol_state
.s_activeq
, pg
, pageq
.queue
);
311 pg
->pqflags
|= PQ_ACTIVE
;
312 pdpol_state
.s_active
++;
316 uvmpdpol_pagedequeue(struct vm_page
*pg
)
319 if (pg
->pqflags
& PQ_ACTIVE
) {
320 KASSERT(mutex_owned(&uvm_pageqlock
));
321 TAILQ_REMOVE(&pdpol_state
.s_activeq
, pg
, pageq
.queue
);
322 pg
->pqflags
&= ~PQ_ACTIVE
;
323 KASSERT(pdpol_state
.s_active
> 0);
324 pdpol_state
.s_active
--;
325 } else if (pg
->pqflags
& PQ_INACTIVE
) {
326 KASSERT(mutex_owned(&uvm_pageqlock
));
327 TAILQ_REMOVE(&pdpol_state
.s_inactiveq
, pg
, pageq
.queue
);
328 pg
->pqflags
&= ~PQ_INACTIVE
;
329 KASSERT(pdpol_state
.s_inactive
> 0);
330 pdpol_state
.s_inactive
--;
335 uvmpdpol_pageenqueue(struct vm_page
*pg
)
338 uvmpdpol_pageactivate(pg
);
342 uvmpdpol_anfree(struct vm_anon
*an
)
347 uvmpdpol_pageisqueued_p(struct vm_page
*pg
)
350 return (pg
->pqflags
& (PQ_ACTIVE
| PQ_INACTIVE
)) != 0;
354 uvmpdpol_estimatepageable(int *active
, int *inactive
)
358 *active
= pdpol_state
.s_active
;
361 *inactive
= pdpol_state
.s_inactive
;
367 min_check(struct uvm_pctparam
*pct
, int t
)
369 struct uvmpdpol_globalstate
*s
= &pdpol_state
;
372 if (pct
!= &s
->s_anonmin
) {
373 total
+= uvm_pctparam_get(&s
->s_anonmin
);
375 if (pct
!= &s
->s_filemin
) {
376 total
+= uvm_pctparam_get(&s
->s_filemin
);
378 if (pct
!= &s
->s_execmin
) {
379 total
+= uvm_pctparam_get(&s
->s_execmin
);
386 #endif /* !defined(PDSIM) */
391 struct uvmpdpol_globalstate
*s
= &pdpol_state
;
393 TAILQ_INIT(&s
->s_activeq
);
394 TAILQ_INIT(&s
->s_inactiveq
);
395 uvm_pctparam_init(&s
->s_inactivepct
, CLOCK_INACTIVEPCT
, NULL
);
396 uvm_pctparam_init(&s
->s_anonmin
, 10, min_check
);
397 uvm_pctparam_init(&s
->s_filemin
, 10, min_check
);
398 uvm_pctparam_init(&s
->s_execmin
, 5, min_check
);
399 uvm_pctparam_init(&s
->s_anonmax
, 80, NULL
);
400 uvm_pctparam_init(&s
->s_filemax
, 50, NULL
);
401 uvm_pctparam_init(&s
->s_execmax
, 30, NULL
);
405 uvmpdpol_reinit(void)
410 uvmpdpol_needsscan_p(void)
413 return pdpol_state
.s_inactive
< pdpol_state
.s_inactarg
;
425 #include <sys/sysctl.h> /* XXX SYSCTL_DESCR */
428 uvmpdpol_sysctlsetup(void)
430 struct uvmpdpol_globalstate
*s
= &pdpol_state
;
432 uvm_pctparam_createsysctlnode(&s
->s_anonmin
, "anonmin",
433 SYSCTL_DESCR("Percentage of physical memory reserved "
434 "for anonymous application data"));
435 uvm_pctparam_createsysctlnode(&s
->s_filemin
, "filemin",
436 SYSCTL_DESCR("Percentage of physical memory reserved "
437 "for cached file data"));
438 uvm_pctparam_createsysctlnode(&s
->s_execmin
, "execmin",
439 SYSCTL_DESCR("Percentage of physical memory reserved "
440 "for cached executable data"));
442 uvm_pctparam_createsysctlnode(&s
->s_anonmax
, "anonmax",
443 SYSCTL_DESCR("Percentage of physical memory which will "
444 "be reclaimed from other usage for "
445 "anonymous application data"));
446 uvm_pctparam_createsysctlnode(&s
->s_filemax
, "filemax",
447 SYSCTL_DESCR("Percentage of physical memory which will "
448 "be reclaimed from other usage for cached "
450 uvm_pctparam_createsysctlnode(&s
->s_execmax
, "execmax",
451 SYSCTL_DESCR("Percentage of physical memory which will "
452 "be reclaimed from other usage for cached "
455 uvm_pctparam_createsysctlnode(&s
->s_inactivepct
, "inactivepct",
456 SYSCTL_DESCR("Percentage of inactive queue of "
457 "the entire (active + inactive) queue"));
460 #endif /* !defined(PDSIM) */
464 pdsim_dump(const char *id
)
468 #endif /* defined(DEBUG) */
470 #endif /* defined(PDSIM) */