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_meter.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_meter.c,v 1.33 2004/10/10 09:57:31 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.33 2004/10/10 09:57:31 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 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()
   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(avg)
   96         struct loadavg *avg;
   97 {
   98         int i, nrun;
   99         struct lwp *l;
  100 
  101         proclist_lock_read();
  102         nrun = 0;
  103         LIST_FOREACH(l, &alllwp, l_list) {
  104                 switch (l->l_stat) {
  105                 case LSSLEEP:
  106                         if (l->l_priority > PZERO || l->l_slptime > 1)
  107                                 continue;
  108                 /* fall through */
  109                 case LSRUN:
  110                 case LSONPROC:
  111                 case LSIDL:
  112                         nrun++;
  113                 }
  114         }
  115         proclist_unlock_read();
  116         for (i = 0; i < 3; i++)
  117                 avg->ldavg[i] = (cexp[i] * avg->ldavg[i] +
  118                     nrun * FSCALE * (FSCALE - cexp[i])) >> FSHIFT;
  119 }
  120 
  121 /*
  122  * sysctl helper routine for the vm.vmmeter node.
  123  */
  124 static int
  125 sysctl_vm_meter(SYSCTLFN_ARGS)
  126 {
  127         struct sysctlnode node;
  128         struct vmtotal vmtotals;
  129 
  130         node = *rnode;
  131         node.sysctl_data = &vmtotals;
  132         uvm_total(&vmtotals);
  133 
  134         return (sysctl_lookup(SYSCTLFN_CALL(&node)));
  135 }
  136 
  137 /*
  138  * sysctl helper routine for the vm.uvmexp node.
  139  */
  140 static int
  141 sysctl_vm_uvmexp(SYSCTLFN_ARGS)
  142 {
  143         struct sysctlnode node;
  144 
  145         node = *rnode;
  146         if (oldp)
  147                 node.sysctl_size = min(*oldlenp, node.sysctl_size);
  148 
  149         return (sysctl_lookup(SYSCTLFN_CALL(&node)));
  150 }
  151 
  152 static int
  153 sysctl_vm_uvmexp2(SYSCTLFN_ARGS)
  154 {
  155         struct sysctlnode node;
  156         struct uvmexp_sysctl u;
  157 
  158         memset(&u, 0, sizeof(u));
  159 
  160         /* Entries here are in order of uvmexp_sysctl, not uvmexp */
  161         u.pagesize = uvmexp.pagesize;
  162         u.pagemask = uvmexp.pagemask;
  163         u.pageshift = uvmexp.pageshift;
  164         u.npages = uvmexp.npages;
  165         u.free = uvmexp.free;
  166         u.active = uvmexp.active;
  167         u.inactive = uvmexp.inactive;
  168         u.paging = uvmexp.paging;
  169         u.wired = uvmexp.wired;
  170         u.zeropages = uvmexp.zeropages;
  171         u.reserve_pagedaemon = uvmexp.reserve_pagedaemon;
  172         u.reserve_kernel = uvmexp.reserve_kernel;
  173         u.freemin = uvmexp.freemin;
  174         u.freetarg = uvmexp.freetarg;
  175         u.inactarg = uvmexp.inactarg;
  176         u.wiredmax = uvmexp.wiredmax;
  177         u.nswapdev = uvmexp.nswapdev;
  178         u.swpages = uvmexp.swpages;
  179         u.swpginuse = uvmexp.swpginuse;
  180         u.swpgonly = uvmexp.swpgonly;
  181         u.nswget = uvmexp.nswget;
  182         u.nanon = uvmexp.nanon;
  183         u.nanonneeded = uvmexp.nanonneeded;
  184         u.nfreeanon = uvmexp.nfreeanon;
  185         u.faults = uvmexp.faults;
  186         u.traps = uvmexp.traps;
  187         u.intrs = uvmexp.intrs;
  188         u.swtch = uvmexp.swtch;
  189         u.softs = uvmexp.softs;
  190         u.syscalls = uvmexp.syscalls;
  191         u.pageins = uvmexp.pageins;
  192         u.swapins = uvmexp.swapins;
  193         u.swapouts = uvmexp.swapouts;
  194         u.pgswapin = uvmexp.pgswapin;
  195         u.pgswapout = uvmexp.pgswapout;
  196         u.forks = uvmexp.forks;
  197         u.forks_ppwait = uvmexp.forks_ppwait;
  198         u.forks_sharevm = uvmexp.forks_sharevm;
  199         u.pga_zerohit = uvmexp.pga_zerohit;
  200         u.pga_zeromiss = uvmexp.pga_zeromiss;
  201         u.zeroaborts = uvmexp.zeroaborts;
  202         u.fltnoram = uvmexp.fltnoram;
  203         u.fltnoanon = uvmexp.fltnoanon;
  204         u.fltpgwait = uvmexp.fltpgwait;
  205         u.fltpgrele = uvmexp.fltpgrele;
  206         u.fltrelck = uvmexp.fltrelck;
  207         u.fltrelckok = uvmexp.fltrelckok;
  208         u.fltanget = uvmexp.fltanget;
  209         u.fltanretry = uvmexp.fltanretry;
  210         u.fltamcopy = uvmexp.fltamcopy;
  211         u.fltnamap = uvmexp.fltnamap;
  212         u.fltnomap = uvmexp.fltnomap;
  213         u.fltlget = uvmexp.fltlget;
  214         u.fltget = uvmexp.fltget;
  215         u.flt_anon = uvmexp.flt_anon;
  216         u.flt_acow = uvmexp.flt_acow;
  217         u.flt_obj = uvmexp.flt_obj;
  218         u.flt_prcopy = uvmexp.flt_prcopy;
  219         u.flt_przero = uvmexp.flt_przero;
  220         u.pdwoke = uvmexp.pdwoke;
  221         u.pdrevs = uvmexp.pdrevs;
  222         u.pdswout = uvmexp.pdswout;
  223         u.pdfreed = uvmexp.pdfreed;
  224         u.pdscans = uvmexp.pdscans;
  225         u.pdanscan = uvmexp.pdanscan;
  226         u.pdobscan = uvmexp.pdobscan;
  227         u.pdreact = uvmexp.pdreact;
  228         u.pdbusy = uvmexp.pdbusy;
  229         u.pdpageouts = uvmexp.pdpageouts;
  230         u.pdpending = uvmexp.pdpending;
  231         u.pddeact = uvmexp.pddeact;
  232         u.anonpages = uvmexp.anonpages;
  233         u.filepages = uvmexp.filepages;
  234         u.execpages = uvmexp.execpages;
  235         u.colorhit = uvmexp.colorhit;
  236         u.colormiss = uvmexp.colormiss;
  237 
  238         node = *rnode;
  239         node.sysctl_data = &u;
  240         node.sysctl_size = sizeof(u);
  241         return (sysctl_lookup(SYSCTLFN_CALL(&node)));
  242 }
  243 
  244 /*
  245  * sysctl helper routine for the vm.{anon,exec,file}{min,max} nodes.
  246  * makes sure that they all correlate properly and none are set too
  247  * large.
  248  */
  249 static int
  250 sysctl_vm_updateminmax(SYSCTLFN_ARGS)
  251 {
  252         int t, error;
  253         struct sysctlnode node;
  254 
  255         node = *rnode;
  256         node.sysctl_data = &t;
  257         t = *(int*)rnode->sysctl_data;
  258         error = sysctl_lookup(SYSCTLFN_CALL(&node));
  259         if (error || newp == NULL)
  260                 return (error);
  261 
  262         if (t < 0 || t > 100)
  263                 return (EINVAL);
  264 
  265 #define UPDATEMIN(a, ap, bp, cp, tp) do { \
  266                 if (tp + uvmexp.bp + uvmexp.cp > 95) \
  267                         return (EINVAL); \
  268                 uvmexp.ap = tp; \
  269                 uvmexp.a = uvmexp.ap * 256 / 100; \
  270         } while (0/*CONSTCOND*/)
  271 
  272 #define UPDATEMAX(a, ap, tp) do { \
  273                 uvmexp.ap = tp; \
  274                 uvmexp.a = tp * 256 / 100; \
  275         } while (0/*CONSTCOND*/)
  276 
  277         switch (rnode->sysctl_num) {
  278         case VM_ANONMIN:
  279                 UPDATEMIN(anonmin, anonminpct, fileminpct, execminpct, t);
  280                 break;
  281         case VM_EXECMIN:
  282                 UPDATEMIN(execmin, execminpct, anonminpct, fileminpct, t);
  283                 break;
  284         case VM_FILEMIN:
  285                 UPDATEMIN(filemin, fileminpct, execminpct, anonminpct, t);
  286                 break;
  287         case VM_ANONMAX:
  288                 UPDATEMAX(anonmax, anonmaxpct, t);
  289                 break;
  290         case VM_EXECMAX:
  291                 UPDATEMAX(execmax, execmaxpct, t);
  292                 break;
  293         case VM_FILEMAX:
  294                 UPDATEMAX(filemax, filemaxpct, t);
  295                 break;
  296         default:
  297                 return (EINVAL);
  298         }
  299 
  300 #undef UPDATEMIN
  301 #undef UPDATEMAX
  302 
  303         return (0);
  304 }
  305 
  306 /*
  307  * uvm_sysctl: sysctl hook into UVM system.
  308  */
  309 SYSCTL_SETUP(sysctl_vm_setup, "sysctl vm subtree setup")
  310 {
  311 
  312         sysctl_createv(clog, 0, NULL, NULL,
  313                        CTLFLAG_PERMANENT,
  314                        CTLTYPE_NODE, "vm", NULL,
  315                        NULL, 0, NULL, 0,
  316                        CTL_VM, CTL_EOL);
  317         sysctl_createv(clog, 0, NULL, NULL,
  318                        CTLFLAG_PERMANENT,
  319                        CTLTYPE_STRUCT, "vmmeter",
  320                        SYSCTL_DESCR("Simple system-wide virtual memory "
  321                                     "statistics"),
  322                        sysctl_vm_meter, 0, NULL, sizeof(struct vmtotal),
  323                        CTL_VM, VM_METER, CTL_EOL);
  324         sysctl_createv(clog, 0, NULL, NULL,
  325                        CTLFLAG_PERMANENT,
  326                        CTLTYPE_STRUCT, "loadavg",
  327                        SYSCTL_DESCR("System load average history"),
  328                        NULL, 0, &averunnable, sizeof(averunnable),
  329                        CTL_VM, VM_LOADAVG, CTL_EOL);
  330         sysctl_createv(clog, 0, NULL, NULL,
  331                        CTLFLAG_PERMANENT,
  332                        CTLTYPE_STRUCT, "uvmexp",
  333                        SYSCTL_DESCR("Detailed system-wide virtual memory "
  334                                     "statistics"),
  335                        sysctl_vm_uvmexp, 0, &uvmexp, sizeof(uvmexp),
  336                        CTL_VM, VM_UVMEXP, CTL_EOL);
  337         sysctl_createv(clog, 0, NULL, NULL,
  338                        CTLFLAG_PERMANENT,
  339                        CTLTYPE_INT, "nkmempages",
  340                        SYSCTL_DESCR("Default number of pages in kmem_map"),
  341                        NULL, 0, &nkmempages, 0,
  342                        CTL_VM, VM_NKMEMPAGES, CTL_EOL);
  343         sysctl_createv(clog, 0, NULL, NULL,
  344                        CTLFLAG_PERMANENT,
  345                        CTLTYPE_STRUCT, "uvmexp2",
  346                        SYSCTL_DESCR("Detailed system-wide virtual memory "
  347                                     "statistics (MI)"),
  348                        sysctl_vm_uvmexp2, 0, NULL, 0,
  349                        CTL_VM, VM_UVMEXP2, CTL_EOL);
  350         sysctl_createv(clog, 0, NULL, NULL,
  351                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
  352                        CTLTYPE_INT, "anonmin",
  353                        SYSCTL_DESCR("Percentage of physical memory reserved "
  354                                     "for anonymous application data"),
  355                        sysctl_vm_updateminmax, 0, &uvmexp.anonminpct, 0,
  356                        CTL_VM, VM_ANONMIN, CTL_EOL);
  357         sysctl_createv(clog, 0, NULL, NULL,
  358                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
  359                        CTLTYPE_INT, "execmin",
  360                        SYSCTL_DESCR("Percentage of physical memory reserved "
  361                                     "for cached executable data"),
  362                        sysctl_vm_updateminmax, 0, &uvmexp.execminpct, 0,
  363                        CTL_VM, VM_EXECMIN, CTL_EOL);
  364         sysctl_createv(clog, 0, NULL, NULL,
  365                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
  366                        CTLTYPE_INT, "filemin",
  367                        SYSCTL_DESCR("Percentage of physical memory reserved "
  368                                     "for cached file data"),
  369                        sysctl_vm_updateminmax, 0, &uvmexp.fileminpct, 0,
  370                        CTL_VM, VM_FILEMIN, CTL_EOL);
  371         sysctl_createv(clog, 0, NULL, NULL,
  372                        CTLFLAG_PERMANENT, CTLTYPE_INT, "maxslp",
  373                        SYSCTL_DESCR("Maximum process sleep time before being "
  374                                     "swapped"),
  375                        NULL, 0, &maxslp, 0,
  376                        CTL_VM, VM_MAXSLP, CTL_EOL);
  377         sysctl_createv(clog, 0, NULL, NULL,
  378                        CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE,
  379                        CTLTYPE_INT, "uspace",
  380                        SYSCTL_DESCR("Number of bytes allocated for a kernel "
  381                                     "stack"),
  382                        NULL, USPACE, NULL, 0,
  383                        CTL_VM, VM_USPACE, CTL_EOL);
  384         sysctl_createv(clog, 0, NULL, NULL,
  385                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
  386                        CTLTYPE_INT, "anonmax",
  387                        SYSCTL_DESCR("Percentage of physical memory which will "
  388                                     "be reclaimed from other usage for "
  389                                     "anonymous application data"),
  390                        sysctl_vm_updateminmax, 0, &uvmexp.anonmaxpct, 0,
  391                        CTL_VM, VM_ANONMAX, CTL_EOL);
  392         sysctl_createv(clog, 0, NULL, NULL,
  393                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
  394                        CTLTYPE_INT, "execmax",
  395                        SYSCTL_DESCR("Percentage of physical memory which will "
  396                                     "be reclaimed from other usage for cached "
  397                                     "executable data"),
  398                        sysctl_vm_updateminmax, 0, &uvmexp.execmaxpct, 0,
  399                        CTL_VM, VM_EXECMAX, CTL_EOL);
  400         sysctl_createv(clog, 0, NULL, NULL,
  401                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
  402                        CTLTYPE_INT, "filemax",
  403                        SYSCTL_DESCR("Percentage of physical memory which will "
  404                                     "be reclaimed from other usage for cached "
  405                                     "file data"),
  406                        sysctl_vm_updateminmax, 0, &uvmexp.filemaxpct, 0,
  407                        CTL_VM, VM_FILEMAX, CTL_EOL);
  408         sysctl_createv(clog, 0, NULL, NULL,
  409                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
  410                        CTLTYPE_INT, "idlezero",
  411                        SYSCTL_DESCR("Whether try to zero pages in idle loop"),
  412                        NULL, 0, &vm_page_zero_enable, 0,
  413                        CTL_VM, CTL_CREATE, CTL_EOL);
  414 }
  415 
  416 /*
  417  * uvm_total: calculate the current state of the system.
  418  */
  419 static void
  420 uvm_total(totalp)
  421         struct vmtotal *totalp;
  422 {
  423         struct lwp *l;
  424 #if 0
  425         struct vm_map_entry *   entry;
  426         struct vm_map *map;
  427         int paging;
  428 #endif
  429 
  430         memset(totalp, 0, sizeof *totalp);
  431 
  432         /*
  433          * calculate process statistics
  434          */
  435 
  436         proclist_lock_read();
  437             LIST_FOREACH(l, &alllwp, l_list) {
  438                 if (l->l_proc->p_flag & P_SYSTEM)
  439                         continue;
  440                 switch (l->l_stat) {
  441                 case 0:
  442                         continue;
  443 
  444                 case LSSLEEP:
  445                 case LSSTOP:
  446                         if (l->l_flag & L_INMEM) {
  447                                 if (l->l_priority <= PZERO)
  448                                         totalp->t_dw++;
  449                                 else if (l->l_slptime < maxslp)
  450                                         totalp->t_sl++;
  451                         } else if (l->l_slptime < maxslp)
  452                                 totalp->t_sw++;
  453                         if (l->l_slptime >= maxslp)
  454                                 continue;
  455                         break;
  456 
  457                 case LSRUN:
  458                 case LSONPROC:
  459                 case LSIDL:
  460                         if (l->l_flag & L_INMEM)
  461                                 totalp->t_rq++;
  462                         else
  463                                 totalp->t_sw++;
  464                         if (l->l_stat == LSIDL)
  465                                 continue;
  466                         break;
  467                 }
  468                 /*
  469                  * note active objects
  470                  */
  471 #if 0
  472                 /*
  473                  * XXXCDC: BOGUS!  rethink this.   in the mean time
  474                  * don't do it.
  475                  */
  476                 paging = 0;
  477                 vm_map_lock(map);
  478                 for (map = &p->p_vmspace->vm_map, entry = map->header.next;
  479                     entry != &map->header; entry = entry->next) {
  480                         if (entry->is_a_map || entry->is_sub_map ||
  481                             entry->object.uvm_obj == NULL)
  482                                 continue;
  483                         /* XXX how to do this with uvm */
  484                 }
  485                 vm_map_unlock(map);
  486                 if (paging)
  487                         totalp->t_pw++;
  488 #endif
  489         }
  490         proclist_unlock_read();
  491         /*
  492          * Calculate object memory usage statistics.
  493          */
  494         totalp->t_free = uvmexp.free;
  495         totalp->t_vm = uvmexp.npages - uvmexp.free + uvmexp.swpginuse;
  496         totalp->t_avm = uvmexp.active + uvmexp.swpginuse;       /* XXX */
  497         totalp->t_rm = uvmexp.npages - uvmexp.free;
  498         totalp->t_arm = uvmexp.active;
  499         totalp->t_vmshr = 0;            /* XXX */
  500         totalp->t_avmshr = 0;           /* XXX */
  501         totalp->t_rmshr = 0;            /* XXX */
  502         totalp->t_armshr = 0;           /* XXX */
  503 }

Cache object: b06e124e9a349817d1e3ebbd0cb852ed


[ 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.