fix bug that can cause recursive .forward files to fail
[unix-history] / usr / src / sys / vm / vm_meter.c
index fb00f29..020aa7b 100644 (file)
-/*     vm_meter.c      3.5     %G%     */
-
-#include "../h/param.h"
-#include "../h/systm.h"
-#include "../h/seg.h"
-#include "../h/dir.h"
-#include "../h/user.h"
-#include "../h/proc.h"
-#include "../h/text.h"
-#include "../h/vm.h"
-#include "../h/cmap.h"
-
-int    maxpgio = MAXPGIO;
-int    maxslp = MAXSLP;
-int    minfree = MINFREE;
-int    desfree = DESFREE;
-int    lotsfree = 0;           /* set to LOTSFREE in main unless adbed */
-int    saferss = SAFERSS;
-int    slowscan = SLOWSCAN;
-int    fastscan = FASTSCAN;
-int    klin = KLIN;
-int    klout = KLOUT;
-int    multprog = -1;          /* so we don't count process 2 */
-
-double avenrun[3];             /* load average, of runnable procs */
-
 /*
 /*
- * The main loop of the scheduling (swapping) process.
- *
- * The basic idea is:
- *     see if anyone wants to be swapped in;
- *     swap out processes until there is room;
- *     swap him in;
- *     repeat.
- * If the paging rate is too high, or the average free memory
- * is very low, then we do not consider swapping anyone in,
- * but rather look for someone to swap out.
+ * Copyright (c) 1982, 1986, 1989, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  *
- * The runout flag is set whenever someone is swapped out.
- * Sched sleeps on it awaiting work.
+ * %sccs.include.redist.c%
  *
  *
- * Sched sleeps on runin whenever it cannot find enough
- * core (by swapping out or otherwise) to fit the
- * selected swapped process.  It is awakened when the
- * core situation changes and in any case once per second.
- *
- * sched DOESN'T ACCOUNT FOR PAGE TABLE SIZE IN CALCULATIONS.
+ *     @(#)vm_meter.c  8.1 (Berkeley) %G%
  */
 
  */
 
-#define        swappable(p) \
-       (((p)->p_flag&(SSYS|SLOCK|SULOCK|SLOAD|SPAGE|SKEEP|SWEXIT|SPHYSIO))==SLOAD)
-
-/* insure non-zero */
-#define        nz(x)   (x != 0 ? x : 1)
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <vm/vm.h>
+#include <sys/sysctl.h>
 
 
-#define        NBIG    4
-#define        MAXNBIG 10
-int    nbig = NBIG;
+struct loadavg averunnable;            /* load average, of runnable procs */
 
 
-struct bigp {
-       struct  proc *bp_proc;
-       int     bp_pri;
-       struct  bigp *bp_link;
-} bigp[MAXNBIG], bplist;
+int    maxslp = MAXSLP;
+int    saferss = SAFERSS;
 
 
-sched()
+void
+vmmeter()
 {
 {
-       register struct proc *rp, *p, *inp;
-       int outpri, inpri, rppri;
-       int sleeper, desparate, deservin, needs, divisor;
-       register struct bigp *bp, *nbp;
-       int biggot, gives;
-
-       /*
-        * Check if paging rate is too high, or average of
-        * free list very low and if so, adjust multiprogramming
-        * load by swapping someone out.
-        *
-        * Avoid glitches: don't hard swap the only process,
-        * and don't swap based on paging rate if there is a reasonable
-        * amount of free memory.
-        */
-loop:
-       (void) spl6();
-       deservin = 0;
-       sleeper = 0;
-       p = 0;
-       if (kmapwnt || (multprog > 1 && avefree < desfree &&
-           (rate.v_pgin + rate.v_pgout > maxpgio || avefree < minfree))) {
-               desparate = 1;
-               goto hardswap;
-       }
-       desparate = 0;
-       /*
-        * Not desparate for core,
-        * look for someone who deserves to be brought in.
-        */
-       outpri = -20000;
-       for (rp = &proc[0]; rp < &proc[NPROC]; rp++) switch(rp->p_stat) {
+       register unsigned *cp, *rp, *sp;
 
 
-       case SRUN:
-               if ((rp->p_flag&SLOAD) == 0) {
-                       rppri = rp->p_time - rp->p_swrss / nz((maxpgio/2) * CLSIZE) +
-                           rp->p_slptime - (rp->p_nice-NZERO)*8;
-                       if (rppri > outpri) {
-                               if (rp->p_poip)
-                                       continue;
-                               if (rp->p_textp && rp->p_textp->x_poip)
-                                       continue;
-                               p = rp;
-                               outpri = rppri;
-                       }
-               }
-               continue;
+       if (time.tv_sec % 5 == 0)
+               loadav(&averunnable);
+       if (proc0.p_slptime > maxslp/2)
+               wakeup((caddr_t)&proc0);
+}
 
 
-       case SSLEEP:
-       case SSTOP:
-               if ((freemem < desfree || rp->p_rssize == 0) &&
-                   rp->p_slptime > maxslp &&
-                   (!rp->p_textp || (rp->p_textp->x_flag&XLOCK)==0) &&
-                   swappable(rp)) {
-                       /*
-                        * Kick out deadwood.
-                        * FOLLOWING 3 LINES MUST BE AT spl6().
-                        */
-                       rp->p_flag &= ~SLOAD;
-                       if (rp->p_stat == SRUN)
-                               remrq(rp);
-                       (void) swapout(rp, rp->p_dsize, rp->p_ssize);
-                       goto loop;
-               }
-               continue;
-       }
+/*
+ * Constants for averages over 1, 5, and 15 minutes
+ * when sampling at 5 second intervals.
+ */
+fixpt_t        cexp[3] = {
+       0.9200444146293232 * FSCALE,    /* exp(-1/12) */
+       0.9834714538216174 * FSCALE,    /* exp(-1/60) */
+       0.9944598480048967 * FSCALE,    /* exp(-1/180) */
+};
 
 
-       /*
-        * No one wants in, so nothing to do.
-        */
-       if (outpri == -20000) {
-               runout++;
-               sleep((caddr_t)&runout, PSWP);
-               goto loop;
-       }
-       (void) spl0();
-       /*
-        * Decide how deserving this guy is.  If he is deserving
-        * we will be willing to work harder to bring him in.
-        * Needs is an estimate of how much core he will need.
-        * If he has been out for a while, then we will
-        * bring him in with 1/2 the core he will need, otherwise
-        * we are conservative.
-        */
-       deservin = 0;
-       divisor = 1;
-       if (outpri > maxslp/2) {
-               deservin = 1;
-               divisor = 2;
-       }
-       needs = p->p_swrss;
-       if (p->p_textp && p->p_textp->x_ccount == 0)
-               needs += p->p_textp->x_swrss;
-       if (freemem - deficit > needs / divisor) {
-               deficit += needs;
-               if (swapin(p))
-                       goto loop;
-               deficit -= imin(needs, deficit);
-       }
+/*
+ * Compute a tenex style load average of a quantity on
+ * 1, 5 and 15 minute intervals.
+ */
+void
+loadav(avg)
+       register struct loadavg *avg;
+{
+       register int i, nrun;
+       register struct proc *p;
 
 
-hardswap:
-       /*
-        * Need resources (kernel map or memory), swap someone out.
-        * Select the nbig largest jobs, then the oldest of these
-        * is ``most likely to get booted.''
-        */
-       (void) spl6();
-       inp = p;
-       sleeper = 0;
-       if (nbig > MAXNBIG)
-               nbig = MAXNBIG;
-       if (nbig < 1)
-               nbig = 1;
-       biggot = 0;
-       bplist.bp_link = 0;
-       for (rp = &proc[0]; rp < &proc[NPROC]; rp++) {
-               if (!swappable(rp))
-                       continue;
-               if (rp->p_stat==SZOMB)
-                       continue;
-               if (rp == inp)
-                       continue;
-               if (rp->p_textp && rp->p_textp->x_flag&XLOCK)
-                       continue;
-               if (rp->p_slptime > maxslp &&
-                   (rp->p_stat==SSLEEP&&rp->p_pri>PZERO||rp->p_stat==SSTOP)) {
-                       if (sleeper < rp->p_slptime) {
-                               p = rp;
-                               sleeper = rp->p_slptime;
-                       }
-               } else if (!sleeper && (rp->p_stat==SRUN||rp->p_stat==SSLEEP)) {
-                       rppri = rp->p_rssize;
-                       if (rp->p_textp)
-                               rppri += rp->p_textp->x_rssize/rp->p_textp->x_ccount;
-                       if (biggot < nbig)
-                               nbp = &bigp[biggot++];
-                       else {
-                               nbp = bplist.bp_link;
-                               if (nbp->bp_pri > rppri)
-                                       continue;
-                               bplist.bp_link = nbp->bp_link;
-                       }
-                       for (bp = &bplist; bp->bp_link; bp = bp->bp_link)
-                               if (rppri < bp->bp_link->bp_pri)
-                                       break;
-                       nbp->bp_link = bp->bp_link;
-                       bp->bp_link = nbp;
-                       nbp->bp_pri = rppri;
-                       nbp->bp_proc = rp;
-               }
-       }
-       if (!sleeper) {
-               p = NULL;
-               inpri = -1000;
-               for (bp = bplist.bp_link; bp; bp = bp->bp_link) {
-                       rp = bp->bp_proc;
-                       rppri = rp->p_time+rp->p_nice-NZERO;
-                       if (rppri >= inpri) {
-                               p = rp;
-                               inpri = rppri;
-                       }
+       for (nrun = 0, p = (struct proc *)allproc; p != NULL; p = p->p_nxt) {
+               switch (p->p_stat) {
+               case SSLEEP:
+                       if (p->p_pri > PZERO || p->p_slptime != 0)
+                               continue;
+                       /* fall through */
+               case SRUN:
+               case SIDL:
+                       nrun++;
                }
        }
                }
        }
-       /*
-        * If we found a long-time sleeper, or we are desparate and
-        * found anyone to swap out, or if someone deserves to come
-        * in and we didn't find a sleeper, but found someone who
-        * has been in core for a reasonable length of time, then
-        * we kick the poor luser out.
-        */
-       if (sleeper || desparate && p || deservin && inpri > maxslp) {
-               p->p_flag &= ~SLOAD;
-               if (p->p_stat == SRUN)
-                       remrq(p);
-               if (desparate) {
-                       /*
-                        * Want to give this space to the rest of
-                        * the processes in core so give them a chance
-                        * by increasing the deficit.
-                        */
-                       gives = p->p_rssize;
-                       if (p->p_textp)
-                               gives += p->p_textp->x_rssize / p->p_textp->x_ccount;
-                       deficit += gives;
-               } else
-                       gives = 0;      /* someone else taketh away */
-               if (swapout(p, p->p_dsize, p->p_ssize) == 0)
-                       deficit -= imin(gives, deficit);
-               goto loop;
-       }
-       /*
-        * Want to swap someone in, but can't
-        * so wait on runin.
-        */
-       (void) spl6();
-       runin++;
-       sleep((caddr_t)&runin, PSWP);
-       goto loop;
+       for (i = 0; i < 3; i++)
+               avg->ldavg[i] = (cexp[i] * avg->ldavg[i] +
+                       nrun * FSCALE * (FSCALE - cexp[i])) >> FSHIFT;
 }
 
 }
 
-vmmeter()
+/*
+ * Attributes associated with virtual memory.
+ */
+vm_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
+       int *name;
+       u_int namelen;
+       void *oldp;
+       size_t *oldlenp;
+       void *newp;
+       size_t newlen;
+       struct proc *p;
 {
 {
-       register unsigned *cp, *rp, *sp;
-
-       deficit -= imin(deficit, imax(deficit / 10, maxpgio / 2));
-       ave(avefree, freemem, 5);
-       /* v_pgin is maintained by clock.c */
-       cp = &cnt.v_first; rp = &rate.v_first; sp = &sum.v_first;
-       while (cp <= &cnt.v_last) {
-               ave(*rp, *cp, 5);
-               *sp += *cp;
-               *cp = 0;
-               rp++, cp++, sp++;
-       }
-       if (time % 5 == 0) {
-               vmtotal();
-               rate.v_swpin = cnt.v_swpin;
-               sum.v_swpin += cnt.v_swpin;
-               cnt.v_swpin = 0;
-               rate.v_swpout = cnt.v_swpout;
-               sum.v_swpout += cnt.v_swpout;
-               cnt.v_swpout = 0;
-       }
-       if (avefree < minfree && runout || proc[0].p_slptime > maxslp/2) {
-               runout = 0;
-               runin = 0;
-               wakeup((caddr_t)&runin);
-               wakeup((caddr_t)&runout);
+       struct vmtotal vmtotals;
+
+       /* all sysctl names at this level are terminal */
+       if (namelen != 1)
+               return (ENOTDIR);               /* overloaded */
+
+       switch (name[0]) {
+       case VM_LOADAVG:
+               averunnable.fscale = FSCALE;
+               return (sysctl_rdstruct(oldp, oldlenp, newp, &averunnable,
+                   sizeof(averunnable)));
+       case VM_METER:
+               vmtotal(&vmtotals);
+               return (sysctl_rdstruct(oldp, oldlenp, newp, &vmtotals,
+                   sizeof(vmtotals)));
+       default:
+               return (EOPNOTSUPP);
        }
        }
+       /* NOTREACHED */
 }
 
 }
 
-vmpago()
+/*
+ * Calculate the current state of the system.
+ * Done on demand from getkerninfo().
+ */
+void
+vmtotal(totalp)
+       register struct vmtotal *totalp;
 {
 {
-       register int vavail;
-       register int scanrate;
+       register struct proc *p;
+       register vm_map_entry_t entry;
+       register vm_object_t object;
+       register vm_map_t map;
+       int paging;
 
 
+       bzero(totalp, sizeof *totalp);
        /*
        /*
-        * Compute new rate for clock; if
-        * nonzero, restart clock.
-        * Rate ranges linearly from one rev per
-        * slowscan seconds when there is lotsfree memory
-        * available to one rev per fastscan seconds when
-        * there is no memory available.
+        * Mark all objects as inactive.
         */
         */
-       nscan = desscan = 0;
-       vavail = freemem - deficit;
-       if (vavail < 0)
-               vavail = 0;
-       if (freemem >= lotsfree)
-               return;
-       scanrate = (slowscan * vavail + fastscan * (lotsfree - vavail)) / nz(lotsfree);
-       desscan = LOOPSIZ / nz(scanrate);
+       simple_lock(&vm_object_list_lock);
+       object = (vm_object_t) queue_first(&vm_object_list);
+       while (!queue_end(&vm_object_list, (queue_entry_t) object)) {
+               object->flags &= ~OBJ_ACTIVE;
+               object = (vm_object_t) queue_next(&object->object_list);
+       }
+       simple_unlock(&vm_object_list_lock);
        /*
        /*
-        * DIVIDE BY 4 TO ACCOUNT FOR RUNNING 4* A SECOND (see clock.c)
+        * Calculate process statistics.
         */
         */
-       desscan /= 4;
-       wakeup((caddr_t)&proc[2]);
-}
-
-vmtotal()
-{
-       register struct proc *p;
-       register struct text *xp;
-       int nrun = 0;
-
-       total.t_vmtxt = 0;
-       total.t_avmtxt = 0;
-       total.t_rmtxt = 0;
-       total.t_armtxt = 0;
-       for (xp = &text[0]; xp < &text[NTEXT]; xp++)
-               if (xp->x_iptr) {
-                       total.t_vmtxt += xp->x_size;
-                       total.t_rmtxt += xp->x_rssize;
-                       for (p = xp->x_caddr; p; p = p->p_xlink)
-                       switch (p->p_stat) {
-
-                       case SSTOP:
-                       case SSLEEP:
-                               if (p->p_slptime >= maxslp)
-                                       continue;
-                               /* fall into... */
-
-                       case SRUN:
-                       case SIDL:
-                               total.t_avmtxt += xp->x_size;
-                               total.t_armtxt += xp->x_rssize;
-                               goto next;
-                       }
-next:
-                       ;
-               }
-       total.t_vm = 0;
-       total.t_avm = 0;
-       total.t_rm = 0;
-       total.t_arm = 0;
-       total.t_rq = 0;
-       total.t_dw = 0;
-       total.t_pw = 0;
-       total.t_sl = 0;
-       total.t_sw = 0;
-       for (p = &proc[0]; p < &proc[NPROC]; p++) {
+       for (p = (struct proc *)allproc; p != NULL; p = p->p_nxt) {
                if (p->p_flag & SSYS)
                        continue;
                if (p->p_flag & SSYS)
                        continue;
-               if (p->p_stat) {
-                       total.t_vm += p->p_dsize + p->p_ssize;
-                       total.t_rm += p->p_rssize;
-                       switch (p->p_stat) {
+               switch (p->p_stat) {
+               case 0:
+                       continue;
 
 
-                       case SSLEEP:
-                       case SSTOP:
+               case SSLEEP:
+               case SSTOP:
+                       if (p->p_flag & SLOAD) {
                                if (p->p_pri <= PZERO)
                                if (p->p_pri <= PZERO)
-                                       nrun++;
-                               if (p->p_flag & SPAGE)
-                                       total.t_pw++;
-                               else if (p->p_flag & SLOAD) {
-                                       if (p->p_pri <= PZERO)
-                                               total.t_dw++;
-                                       else if (p->p_slptime < maxslp)
-                                               total.t_sl++;
-                               } else if (p->p_slptime < maxslp)
-                                       total.t_sw++;
-                               if (p->p_slptime < maxslp)
-                                       goto active;
-                               break;
-
-                       case SRUN:
-                       case SIDL:
-                               nrun++;
-                               if (p->p_flag & SLOAD)
-                                       total.t_rq++;
-                               else
-                                       total.t_sw++;
-active:
-                               total.t_avm += p->p_dsize + p->p_ssize;
-                               total.t_arm += p->p_rssize;
-                               break;
+                                       totalp->t_dw++;
+                               else if (p->p_slptime < maxslp)
+                                       totalp->t_sl++;
+                       } else if (p->p_slptime < maxslp)
+                               totalp->t_sw++;
+                       if (p->p_slptime >= maxslp)
+                               continue;
+                       break;
+
+               case SRUN:
+               case SIDL:
+                       if (p->p_flag & SLOAD)
+                               totalp->t_rq++;
+                       else
+                               totalp->t_sw++;
+                       if (p->p_stat == SIDL)
+                               continue;
+                       break;
+               }
+               /*
+                * Note active objects.
+                */
+               paging = 0;
+               for (map = &p->p_vmspace->vm_map, entry = map->header.next;
+                    entry != &map->header; entry = entry->next) {
+                       if (entry->is_a_map || entry->is_sub_map ||
+                           entry->object.vm_object == NULL)
+                               continue;
+                       entry->object.vm_object->flags |= OBJ_ACTIVE;
+                       paging |= entry->object.vm_object->paging_in_progress;
+               }
+               if (paging)
+                       totalp->t_pw++;
+       }
+       /*
+        * Calculate object memory usage statistics.
+        */
+       simple_lock(&vm_object_list_lock);
+       object = (vm_object_t) queue_first(&vm_object_list);
+       while (!queue_end(&vm_object_list, (queue_entry_t) object)) {
+               totalp->t_vm += num_pages(object->size);
+               totalp->t_rm += object->resident_page_count;
+               if (object->flags & OBJ_ACTIVE) {
+                       totalp->t_avm += num_pages(object->size);
+                       totalp->t_arm += object->resident_page_count;
+               }
+               if (object->ref_count > 1) {
+                       /* shared object */
+                       totalp->t_vmshr += num_pages(object->size);
+                       totalp->t_rmshr += object->resident_page_count;
+                       if (object->flags & OBJ_ACTIVE) {
+                               totalp->t_avmshr += num_pages(object->size);
+                               totalp->t_armshr += object->resident_page_count;
                        }
                }
                        }
                }
+               object = (vm_object_t) queue_next(&object->object_list);
        }
        }
-       total.t_vm += total.t_vmtxt;
-       total.t_avm += total.t_avmtxt;
-       total.t_rm += total.t_rmtxt;
-       total.t_arm += total.t_armtxt;
-       total.t_free = avefree;
-       loadav(avenrun, nrun);
-}
-
-/*
- * Constants for averages over 1, 5, and 15 minutes
- * when sampling at 5 second intervals.
- */
-double cexp[3] = {
-       0.9200444146293232,     /* exp(-1/12) */
-       0.9834714538216174,     /* exp(-1/60) */
-       0.9944598480048967,     /* exp(-1/180) */
-};
-
-/*
- * Compute a tenex style load average of a quantity on
- * 1, 5 and 15 minute intervals.
- */
-loadav(avg, n)
-       register double *avg;
-       int n;
-{
-       register int i;
-
-       for (i = 0; i < 3; i++)
-               avg[i] = cexp[i] * avg[i] + n * (1.0 - cexp[i]);
+       totalp->t_free = cnt.v_free_count;
 }
 }