The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/uvm/uvm_pdpolicy_clock.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: uvm_pdpolicy_clock.c,v 1.12 2008/06/04 12:41:40 ad Exp $       */
    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.
   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
   25  *      its contributors.
   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.
   29  *
   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
   40  * SUCH DAMAGE.
   41  *
   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
   44  *
   45  *
   46  * Copyright (c) 1987, 1990 Carnegie-Mellon University.
   47  * All rights reserved.
   48  *
   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.
   54  *
   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.
   58  *
   59  * Carnegie Mellon requests users of this software to return to
   60  *
   61  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
   62  *  School of Computer Science
   63  *  Carnegie Mellon University
   64  *  Pittsburgh PA 15213-3890
   65  *
   66  * any improvements or extensions that they make and grant Carnegie the
   67  * rights to redistribute these changes.
   68  */
   69 
   70 #if defined(PDSIM)
   71 
   72 #include "pdsim.h"
   73 
   74 #else /* defined(PDSIM) */
   75 
   76 #include <sys/cdefs.h>
   77 __KERNEL_RCSID(0, "$NetBSD: uvm_pdpolicy_clock.c,v 1.12 2008/06/04 12:41:40 ad Exp $");
   78 
   79 #include <sys/param.h>
   80 #include <sys/proc.h>
   81 #include <sys/systm.h>
   82 #include <sys/kernel.h>
   83 
   84 #include <uvm/uvm.h>
   85 #include <uvm/uvm_pdpolicy.h>
   86 #include <uvm/uvm_pdpolicy_impl.h>
   87 
   88 #endif /* defined(PDSIM) */
   89 
   90 #define PQ_INACTIVE     PQ_PRIVATE1     /* page is in inactive list */
   91 #define PQ_ACTIVE       PQ_PRIVATE2     /* page is in active list */
   92 
   93 #if !defined(CLOCK_INACTIVEPCT)
   94 #define CLOCK_INACTIVEPCT       33
   95 #endif /* !defined(CLOCK_INACTIVEPCT) */
   96 
   97 struct uvmpdpol_globalstate {
   98         struct pglist s_activeq;        /* allocated pages, in use */
   99         struct pglist s_inactiveq;      /* pages between the clock hands */
  100         int s_active;
  101         int s_inactive;
  102         int s_inactarg;
  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;
  110 };
  111 
  112 struct uvmpdpol_scanstate {
  113         bool ss_first;
  114         bool ss_anonreact, ss_filereact, ss_execreact;
  115         struct vm_page *ss_nextpg;
  116 };
  117 
  118 static struct uvmpdpol_globalstate pdpol_state;
  119 static struct uvmpdpol_scanstate pdpol_scanstate;
  120 
  121 PDPOL_EVCNT_DEFINE(reactexec)
  122 PDPOL_EVCNT_DEFINE(reactfile)
  123 PDPOL_EVCNT_DEFINE(reactanon)
  124 
  125 static void
  126 clock_tune(void)
  127 {
  128         struct uvmpdpol_globalstate *s = &pdpol_state;
  129 
  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;
  134         }
  135 }
  136 
  137 void
  138 uvmpdpol_scaninit(void)
  139 {
  140         struct uvmpdpol_globalstate *s = &pdpol_state;
  141         struct uvmpdpol_scanstate *ss = &pdpol_scanstate;
  142         int t;
  143         bool anonunder, fileunder, execunder;
  144         bool anonover, fileover, execover;
  145         bool anonreact, filereact, execreact;
  146 
  147         /*
  148          * decide which types of pages we want to reactivate instead of freeing
  149          * to keep usage within the minimum and maximum usage limits.
  150          */
  151 
  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;
  164         }
  165         ss->ss_anonreact = anonreact;
  166         ss->ss_filereact = filereact;
  167         ss->ss_execreact = execreact;
  168 
  169         ss->ss_first = true;
  170 }
  171 
  172 struct vm_page *
  173 uvmpdpol_selectvictim(void)
  174 {
  175         struct uvmpdpol_scanstate *ss = &pdpol_scanstate;
  176         struct vm_page *pg;
  177 
  178         KASSERT(mutex_owned(&uvm_pageqlock));
  179 
  180         while (/* CONSTCOND */ 1) {
  181                 struct vm_anon *anon;
  182                 struct uvm_object *uobj;
  183 
  184                 if (ss->ss_first) {
  185                         pg = TAILQ_FIRST(&pdpol_state.s_inactiveq);
  186                         ss->ss_first = false;
  187                 } else {
  188                         pg = ss->ss_nextpg;
  189                         if (pg != NULL && (pg->pqflags & PQ_INACTIVE) == 0) {
  190                                 pg = TAILQ_FIRST(&pdpol_state.s_inactiveq);
  191                         }
  192                 }
  193                 if (pg == NULL) {
  194                         break;
  195                 }
  196                 ss->ss_nextpg = TAILQ_NEXT(pg, pageq.queue);
  197 
  198                 uvmexp.pdscans++;
  199 
  200                 /*
  201                  * move referenced pages back to active queue and
  202                  * skip to next page.
  203                  */
  204 
  205                 if (pmap_is_referenced(pg)) {
  206                         uvmpdpol_pageactivate(pg);
  207                         uvmexp.pdreact++;
  208                         continue;
  209                 }
  210 
  211                 anon = pg->uanon;
  212                 uobj = pg->uobject;
  213 
  214                 /*
  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.
  220                  */
  221 
  222                 if (uobj && UVM_OBJ_IS_VTEXT(uobj) && ss->ss_execreact) {
  223                         uvmpdpol_pageactivate(pg);
  224                         PDPOL_EVCNT_INCR(reactexec);
  225                         continue;
  226                 }
  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);
  231                         continue;
  232                 }
  233                 if ((anon || UVM_OBJ_IS_AOBJ(uobj)) && ss->ss_anonreact) {
  234                         uvmpdpol_pageactivate(pg);
  235                         PDPOL_EVCNT_INCR(reactanon);
  236                         continue;
  237                 }
  238 
  239                 break;
  240         }
  241 
  242         return pg;
  243 }
  244 
  245 void
  246 uvmpdpol_balancequeue(int swap_shortage)
  247 {
  248         int inactive_shortage;
  249         struct vm_page *p, *nextpg;
  250 
  251         /*
  252          * we have done the scan to get free pages.   now we work on meeting
  253          * our inactive target.
  254          */
  255 
  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);
  259              p = nextpg) {
  260                 nextpg = TAILQ_NEXT(p, pageq.queue);
  261 
  262                 /*
  263                  * if there's a shortage of swap slots, try to free it.
  264                  */
  265 
  266                 if (swap_shortage > 0 && (p->pqflags & PQ_SWAPBACKED) != 0) {
  267                         if (uvmpd_trydropswap(p)) {
  268                                 swap_shortage--;
  269                         }
  270                 }
  271 
  272                 /*
  273                  * if there's a shortage of inactive pages, deactivate.
  274                  */
  275 
  276                 if (inactive_shortage > 0) {
  277                         /* no need to check wire_count as pg is "active" */
  278                         uvmpdpol_pagedeactivate(p);
  279                         uvmexp.pddeact++;
  280                         inactive_shortage--;
  281                 }
  282         }
  283 }
  284 
  285 void
  286 uvmpdpol_pagedeactivate(struct vm_page *pg)
  287 {
  288 
  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--;
  295         }
  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++;
  302         }
  303 }
  304 
  305 void
  306 uvmpdpol_pageactivate(struct vm_page *pg)
  307 {
  308 
  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++;
  313 }
  314 
  315 void
  316 uvmpdpol_pagedequeue(struct vm_page *pg)
  317 {
  318 
  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--;
  331         }
  332 }
  333 
  334 void
  335 uvmpdpol_pageenqueue(struct vm_page *pg)
  336 {
  337 
  338         uvmpdpol_pageactivate(pg);
  339 }
  340 
  341 void
  342 uvmpdpol_anfree(struct vm_anon *an)
  343 {
  344 }
  345 
  346 bool
  347 uvmpdpol_pageisqueued_p(struct vm_page *pg)
  348 {
  349 
  350         return (pg->pqflags & (PQ_ACTIVE | PQ_INACTIVE)) != 0;
  351 }
  352 
  353 void
  354 uvmpdpol_estimatepageable(int *active, int *inactive)
  355 {
  356 
  357         if (active) {
  358                 *active = pdpol_state.s_active;
  359         }
  360         if (inactive) {
  361                 *inactive = pdpol_state.s_inactive;
  362         }
  363 }
  364 
  365 #if !defined(PDSIM)
  366 static int
  367 min_check(struct uvm_pctparam *pct, int t)
  368 {
  369         struct uvmpdpol_globalstate *s = &pdpol_state;
  370         int total = t;
  371 
  372         if (pct != &s->s_anonmin) {
  373                 total += uvm_pctparam_get(&s->s_anonmin);
  374         }
  375         if (pct != &s->s_filemin) {
  376                 total += uvm_pctparam_get(&s->s_filemin);
  377         }
  378         if (pct != &s->s_execmin) {
  379                 total += uvm_pctparam_get(&s->s_execmin);
  380         }
  381         if (total > 95) {
  382                 return EINVAL;
  383         }
  384         return 0;
  385 }
  386 #endif /* !defined(PDSIM) */
  387 
  388 void
  389 uvmpdpol_init(void)
  390 {
  391         struct uvmpdpol_globalstate *s = &pdpol_state;
  392 
  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);
  402 }
  403 
  404 void
  405 uvmpdpol_reinit(void)
  406 {
  407 }
  408 
  409 bool
  410 uvmpdpol_needsscan_p(void)
  411 {
  412 
  413         return pdpol_state.s_inactive < pdpol_state.s_inactarg;
  414 }
  415 
  416 void
  417 uvmpdpol_tune(void)
  418 {
  419 
  420         clock_tune();
  421 }
  422 
  423 #if !defined(PDSIM)
  424 
  425 #include <sys/sysctl.h> /* XXX SYSCTL_DESCR */
  426 
  427 void
  428 uvmpdpol_sysctlsetup(void)
  429 {
  430         struct uvmpdpol_globalstate *s = &pdpol_state;
  431 
  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"));
  441 
  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 "
  449             "file data"));
  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 "
  453             "executable data"));
  454 
  455         uvm_pctparam_createsysctlnode(&s->s_inactivepct, "inactivepct",
  456             SYSCTL_DESCR("Percentage of inactive queue of "
  457             "the entire (active + inactive) queue"));
  458 }
  459 
  460 #endif /* !defined(PDSIM) */
  461 
  462 #if defined(PDSIM)
  463 void
  464 pdsim_dump(const char *id)
  465 {
  466 #if defined(DEBUG)
  467         /* XXX */
  468 #endif /* defined(DEBUG) */
  469 }
  470 #endif /* defined(PDSIM) */

Cache object: e3cfd27fedc853b9636b53784505c8fa


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.