-/* vm_meter.c 3.6 %G% */
+/*
+ * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#)vm_meter.c 7.8 (Berkeley) %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"
+#include "param.h"
+#include "systm.h"
+#include "user.h"
+#include "proc.h"
+#include "text.h"
+#include "vm.h"
+#include "kernel.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;
+
+/*
+ * The following parameters control operation of the page replacement
+ * algorithm. They are initialized to 0, and then computed at boot time
+ * based on the size of the system. If they are patched non-zero in
+ * a loaded vmunix they are left alone and may thus be changed per system
+ * using adb on the loaded system.
+ */
+int maxpgio = 0;
+int minfree = 0;
+int desfree = 0;
+int lotsfree = 0;
+int slowscan = 0;
+int fastscan = 0;
int klin = KLIN;
+int klseql = KLSEQL;
+int klsdist = KLSDIST;
+int kltxt = KLTXT;
int klout = KLOUT;
int multprog = -1; /* so we don't count process 2 */
-double avenrun[3]; /* load average, of runnable procs */
+fixpt_t averunnable[3]; /* load average, of runnable procs */
/*
* The main loop of the scheduling (swapping) process.
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();
+ wantin = 0;
deservin = 0;
sleeper = 0;
p = 0;
- if (kmapwnt || (multprog > 1 && avefree < desfree &&
- (rate.v_pgin + rate.v_pgout > maxpgio || avefree < minfree))) {
+ /*
+ * See if paging system is overloaded; if so swap someone out.
+ * Conditions for hard outswap are:
+ * if need kernel map (mix it up).
+ * or
+ * 1. if there are at least 2 runnable processes (on the average)
+ * and 2. the paging rate is excessive or memory is now VERY low.
+ * and 3. the short (5-second) and longer (30-second) average
+ * memory is less than desirable.
+ */
+ if (kmapwnt ||
+ (averunnable[0] >= 2 * FSCALE &&
+ imax(avefree, avefree30) < desfree &&
+ (rate.v_pgin + rate.v_pgout > maxpgio || avefree < minfree))) {
desperate = 1;
goto hardswap;
}
* look for someone who deserves to be brought in.
*/
outpri = -20000;
- for (rp = &proc[0]; rp < &proc[NPROC]; rp++) switch(rp->p_stat) {
+ for (rp = allproc; rp != NULL; rp = rp->p_nxt) switch(rp->p_stat) {
case SRUN:
if ((rp->p_flag&SLOAD) == 0) {
- rppri = rp->p_time - rp->p_swrss / nz((maxpgio/2) * CLSIZE) +
+ rppri = rp->p_time -
+ rp->p_swrss / nz((maxpgio/2) * (klin * CLSIZE)) +
rp->p_slptime - (rp->p_nice-NZERO)*8;
if (rppri > outpri) {
if (rp->p_poip)
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;
+ (void) swapout(rp, rp->p_dsize, rp->p_mmsize, rp->p_ssize);
}
continue;
}
/*
- * No one wants in, so nothing to do.
+ * If something came ready after we checked it,
+ * wantin will be set. Otherwise,
+ * no one wants in, so nothing to do.
*/
if (outpri == -20000) {
- runout++;
- sleep((caddr_t)&runout, PSWP);
+ (void) splhigh();
+ if (wantin == 0) {
+ runout++;
+ sleep((caddr_t)&runout, PSWP);
+ }
+ (void) spl0();
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 = p->p_swrss;
if (p->p_textp && p->p_textp->x_ccount == 0)
needs += p->p_textp->x_swrss;
+ needs = imin(needs, lotsfree);
if (freemem - deficit > needs / divisor) {
deficit += needs;
if (swapin(p))
* 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 = 1;
biggot = 0;
bplist.bp_link = 0;
- for (rp = &proc[0]; rp < &proc[NPROC]; rp++) {
+ for (rp = allproc; rp != NULL; rp = rp->p_nxt) {
if (!swappable(rp))
continue;
- if (rp->p_stat==SZOMB)
- continue;
if (rp == inp)
continue;
if (rp->p_textp && rp->p_textp->x_flag&XLOCK)
* we kick the poor luser out.
*/
if (sleeper || desperate && p || deservin && inpri > maxslp) {
+ (void) splhigh();
p->p_flag &= ~SLOAD;
if (p->p_stat == SRUN)
remrq(p);
+ (void) spl0();
if (desperate) {
/*
* Want to give this space to the rest of
gives = p->p_rssize;
if (p->p_textp)
gives += p->p_textp->x_rssize / p->p_textp->x_ccount;
+ gives = imin(gives, lotsfree);
deficit += gives;
} else
gives = 0; /* someone else taketh away */
- if (swapout(p, p->p_dsize, p->p_ssize) == 0)
+ if (swapout(p, p->p_dsize, p->p_mmsize, p->p_ssize) == 0)
deficit -= imin(gives, deficit);
- goto loop;
+ else
+ goto loop;
}
/*
* Want to swap someone in, but can't
* so wait on runin.
*/
- (void) spl6();
+ (void) splhigh();
runin++;
sleep((caddr_t)&runin, PSWP);
+ (void) spl0();
goto loop;
}
{
register unsigned *cp, *rp, *sp;
- deficit -= imin(deficit, imax(deficit / 10, maxpgio / 2));
+ deficit -= imin(deficit,
+ imax(deficit / 10, ((klin * CLSIZE) / 2) * maxpgio / 2));
ave(avefree, freemem, 5);
+ ave(avefree30, freemem, 30);
/* v_pgin is maintained by clock.c */
cp = &cnt.v_first; rp = &rate.v_first; sp = &sum.v_first;
while (cp <= &cnt.v_last) {
*cp = 0;
rp++, cp++, sp++;
}
- if (time % 5 == 0) {
+ if (time.tv_sec % 5 == 0) {
vmtotal();
rate.v_swpin = cnt.v_swpin;
sum.v_swpin += cnt.v_swpin;
}
}
-vmpago()
+/*
+ * Schedule rate for paging.
+ * Rate is linear interpolation between
+ * slowscan with lotsfree and fastscan when out of memory.
+ */
+schedpaging()
{
register int vavail;
- register int scanrate;
- /*
- * 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.
- */
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);
- /*
- * DIVIDE BY 4 TO ACCOUNT FOR RUNNING 4* A SECOND (see clock.c)
- */
- desscan /= 4;
- wakeup((caddr_t)&proc[2]);
+ if (freemem < lotsfree) {
+ desscan = (slowscan * vavail + fastscan * (lotsfree - vavail)) /
+ nz(lotsfree) / RATETOSCHEDPAGING;
+ wakeup((caddr_t)&proc[2]);
+ }
+ timeout(schedpaging, (caddr_t)0, hz / RATETOSCHEDPAGING);
}
vmtotal()
total.t_avmtxt = 0;
total.t_rmtxt = 0;
total.t_armtxt = 0;
- for (xp = &text[0]; xp < &text[NTEXT]; xp++)
- if (xp->x_iptr) {
+ for (xp = text; xp < textNTEXT; xp++)
+ if (xp->x_vptr) {
total.t_vmtxt += xp->x_size;
total.t_rmtxt += xp->x_rssize;
for (p = xp->x_caddr; p; p = p->p_xlink)
total.t_pw = 0;
total.t_sl = 0;
total.t_sw = 0;
- for (p = &proc[0]; p < &proc[NPROC]; p++) {
+ for (p = 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;
+ if (p->p_stat != SZOMB) {
+ 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)
+ if (p->p_pri <= PZERO && p->p_slptime == 0)
nrun++;
+ /* fall through */
+ case SSTOP:
if (p->p_flag & SPAGE)
total.t_pw++;
else if (p->p_flag & SLOAD) {
total.t_rm += total.t_rmtxt;
total.t_arm += total.t_armtxt;
total.t_free = avefree;
- loadav(avenrun, nrun);
+ loadav(averunnable, 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) */
+fixpt_t cexp[3] = {
+ 0.9200444146293232 * FSCALE, /* exp(-1/12) */
+ 0.9834714538216174 * FSCALE, /* exp(-1/60) */
+ 0.9944598480048967 * FSCALE, /* exp(-1/180) */
};
/*
* 1, 5 and 15 minute intervals.
*/
loadav(avg, n)
- register double *avg;
+ register fixpt_t *avg;
int n;
{
register int i;
for (i = 0; i < 3; i++)
- avg[i] = cexp[i] * avg[i] + n * (1.0 - cexp[i]);
+ avg[i] = (cexp[i] * avg[i] + n * FSCALE * (FSCALE - cexp[i]))
+ >> FSHIFT;
+#if defined(COMPAT_43) && (defined(vax) || defined(tahoe))
+ for (i = 0; i < 3; i++)
+ avenrun[i] = (double) averunnable[i] / FSCALE;
+#endif /* COMPAT_43 */
}