X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/7eb2e67e9c11cdf5da775af544c97e4a5768474a..a2cdf9f6b08eceef2637b965669f0e87065b27fb:/usr/src/sys/vm/vm_meter.c diff --git a/usr/src/sys/vm/vm_meter.c b/usr/src/sys/vm/vm_meter.c index addb677276..020aa7b3c6 100644 --- a/usr/src/sys/vm/vm_meter.c +++ b/usr/src/sys/vm/vm_meter.c @@ -1,446 +1,200 @@ -/* vm_meter.c 4.5 81/04/17 */ - -#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 +#include +#include +#include +#include +#include -#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, desperate, 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: - wantin = 0; - deservin = 0; - sleeper = 0; - p = 0; - if (kmapwnt || (multprog > 1 && avefree < desfree && - (rate.v_pgin + rate.v_pgout > maxpgio || avefree < minfree))) { - desperate = 1; - goto hardswap; - } - desperate = 0; - /* - * Not desperate for core, - * look for someone who deserves to be brought in. - */ - outpri = -20000; - for (rp = proc; rp < procNPROC; 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. - */ - (void) spl6(); - rp->p_flag &= ~SLOAD; - if (rp->p_stat == SRUN) - remrq(rp); - (void) spl0(); - (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) { - (void) spl6(); - if (wantin) { - wantin = 0; - sleep((caddr_t)&lbolt, PSWP); - } else { - runout++; - sleep((caddr_t)&runout, PSWP); - } - (void) spl0(); - goto loop; - } - /* - * 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.'' - */ - inp = p; - sleeper = 0; - if (nbig > MAXNBIG) - nbig = MAXNBIG; - if (nbig < 1) - nbig = 1; - biggot = 0; - bplist.bp_link = 0; - for (rp = proc; rp < procNPROC; 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; + 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 (!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; - } - } - } - /* - * If we found a long-time sleeper, or we are desperate 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 || desperate && p || deservin && inpri > maxslp) { - (void) spl6(); - p->p_flag &= ~SLOAD; - if (p->p_stat == SRUN) - remrq(p); - (void) spl0(); - if (desperate) { - /* - * 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); - (void) spl0(); - 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; xp < textNTEXT; 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; p < procNPROC; 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) { + 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) - 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; }