-/* vm_meter.c 3.4 %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_stat) {
- total.t_vm += p->p_dsize + p->p_ssize;
- total.t_rm += p->p_rssize;
- switch (p->p_stat) {
-
- case SSLEEP:
- case SSTOP:
- 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;
+ switch (p->p_stat) {
+ case 0:
+ continue;
- 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;
+ case SSLEEP:
+ case SSTOP:
+ if (p->p_flag & SLOAD) {
+ if (p->p_pri <= PZERO)
+ 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;
}