|
|
1.1 ! root 1: #include "sys/param.h" ! 2: #include "sys/systm.h" ! 3: #include "sys/user.h" ! 4: #include "sys/proc.h" ! 5: #include "sys/text.h" ! 6: #include "sys/vm.h" ! 7: #include "sys/cmap.h" ! 8: #include "sys/conf.h" ! 9: #include "sys/buf.h" /* just for bclnlist! */ ! 10: ! 11: int maxslp = MAXSLP; ! 12: int saferss = SAFERSS; ! 13: ! 14: /* ! 15: * The following parameters control operation of the page replacement ! 16: * algorithm. They are initialized to 0, and then computed at boot time ! 17: * based on the size of the system. If they are patched non-zero in ! 18: * a loaded vmunix they are left alone and may thus be changed per system ! 19: * using adb on the loaded system. ! 20: */ ! 21: int maxpgio = 0; ! 22: int minfree = 0; ! 23: int desfree = 0; ! 24: int lotsfree = 0; ! 25: int slowscan = 0; ! 26: int fastscan = 0; ! 27: int klin = KLIN; ! 28: int klseql = KLSEQL; ! 29: int klsdist = KLSDIST; ! 30: int kltxt = KLTXT; ! 31: int klout = KLOUT; ! 32: ! 33: double avenrun[3]; /* load average, of runnable procs */ ! 34: ! 35: int vmmeter(); ! 36: ! 37: /* ! 38: * Setup the paging constants for the clock algorithm. ! 39: * Called after the system is initialized and the amount of memory ! 40: * and number of paging devices is known. ! 41: */ ! 42: setupclock() ! 43: { ! 44: ! 45: /* ! 46: * Setup thresholds for paging: ! 47: * lotsfree is threshold where paging daemon turns on ! 48: * desfree is amount of memory desired free. if less ! 49: * than this for extended period, do swapping ! 50: * minfree is minimal amount of free memory which is ! 51: * tolerable. ! 52: * ! 53: * Strategy of 4/22/81: ! 54: * lotsfree is 1/4 of memory free. ! 55: * desfree is 200k bytes, but at most 1/8 of memory ! 56: * minfree is 64k bytes, but at most 1/2 of desfree ! 57: */ ! 58: if (lotsfree == 0) ! 59: lotsfree = LOOPPAGES / 4; ! 60: if (desfree == 0) { ! 61: desfree = (200*1024) / NBPG; ! 62: if (desfree > LOOPPAGES / 8) ! 63: desfree = LOOPPAGES / 8; ! 64: } ! 65: if (minfree == 0) { ! 66: minfree = (64*1024) / NBPG; ! 67: if (minfree > desfree/2) ! 68: minfree = desfree / 2; ! 69: } ! 70: ! 71: /* ! 72: * Maxpgio thresholds how much paging is acceptable. ! 73: * This figures that 2/3 busy on an arm is all that is ! 74: * tolerable for paging. We assume one operation per disk rev. ! 75: */ ! 76: if (maxpgio == 0) ! 77: maxpgio = (DISKRPM * 2) / 3; ! 78: ! 79: /* ! 80: * Clock to scan using max of ~~10% of processor time for sampling, ! 81: * this estimated to allow maximum of 200 samples per second. ! 82: * This yields a ``fastscan'' of roughly (with CLSIZE=2): ! 83: * <=1m 2m 3m 4m 8m ! 84: * 5s 10s 15s 20s 40s ! 85: */ ! 86: if (fastscan == 0) ! 87: fastscan = (LOOPPAGES/CLSIZE) / 200; ! 88: if (fastscan < 5) ! 89: fastscan = 5; ! 90: if (nswdevt == 2) ! 91: maxpgio = (maxpgio * 3) / 2; ! 92: ! 93: /* ! 94: * Set slow scan time to 1/2 the fast scan time. ! 95: */ ! 96: if (slowscan == 0) ! 97: slowscan = 2 * fastscan; ! 98: vmpago(); /* to fire off timeout */ ! 99: timeout(vmmeter, (caddr_t)0, 11); /* offset from 1-sec clock uproar */ ! 100: } ! 101: ! 102: /* ! 103: * The main loop of the scheduling (swapping) process. ! 104: * ! 105: * The basic idea is: ! 106: * see if anyone wants to be swapped in; ! 107: * swap out processes until there is room; ! 108: * swap him in; ! 109: * repeat. ! 110: * If the paging rate is too high, or the average free memory ! 111: * is very low, then we do not consider swapping anyone in, ! 112: * but rather look for someone to swap out. ! 113: * ! 114: * The runout flag is set whenever someone is swapped out. ! 115: * Sched sleeps on it awaiting work. ! 116: * ! 117: * Sched sleeps on runin whenever it cannot find enough ! 118: * core (by swapping out or otherwise) to fit the ! 119: * selected swapped process. It is awakened when the ! 120: * core situation changes and in any case once per second. ! 121: * ! 122: * sched DOESN'T ACCOUNT FOR PAGE TABLE SIZE IN CALCULATIONS. ! 123: */ ! 124: ! 125: #define swappable(p) (((p)->p_flag & \ ! 126: (SSYS|SLOCK|SULOCK|SLOAD|SPAGE|SKEEP|SWEXIT|SPHYSIO|SPROCIO)) == SLOAD) ! 127: ! 128: /* insure non-zero */ ! 129: #define nz(x) (x != 0 ? x : 1) ! 130: ! 131: #define NBIG 4 ! 132: #define MAXNBIG 10 ! 133: int nbig = NBIG; ! 134: ! 135: struct bigp { ! 136: struct proc *bp_proc; ! 137: int bp_pri; ! 138: struct bigp *bp_link; ! 139: } bigp[MAXNBIG], bplist; ! 140: ! 141: sched() ! 142: { ! 143: register struct proc *rp, *p, *inp; ! 144: int outpri, inpri, rppri; ! 145: int sleeper, desperate, deservin, needs, divisor; ! 146: register struct bigp *bp, *nbp; ! 147: int biggot, gives; ! 148: ! 149: loop: ! 150: wantin = 0; ! 151: deservin = 0; ! 152: sleeper = 0; ! 153: p = 0; ! 154: /* ! 155: * See if paging system is overloaded; if so swap someone out. ! 156: * Conditions for hard outswap are: ! 157: * if need kernel map (mix it up). ! 158: * or ! 159: * 1. if there are at least 2 runnable processes (on the average) ! 160: * and 2. the paging rate is excessive or memory is now VERY low. ! 161: * and 3. the short (5-second) and longer (30-second) average ! 162: * memory is less than desirable. ! 163: */ ! 164: if (kmapwnt || (avenrun[0] >= 2 && imax(avefree, avefree30) < desfree && ! 165: (rate.v_pgin + rate.v_pgout > maxpgio || avefree < minfree))) { ! 166: desperate = 1; ! 167: goto hardswap; ! 168: } ! 169: desperate = 0; ! 170: /* ! 171: * Not desperate for core, ! 172: * look for someone who deserves to be brought in. ! 173: */ ! 174: outpri = -20000; ! 175: for (rp = proc; rp < procNPROC; rp++) { ! 176: if (rp->p_stat == 0) ! 177: continue; ! 178: switch(rp->p_flag&SPROCIO ? SRUN : rp->p_stat) { ! 179: case SRUN: ! 180: if ((rp->p_flag&SLOAD) == 0) { ! 181: rppri = rp->p_flag&SPROCIO ? 99999 : rp->p_time - ! 182: rp->p_swrss / nz((maxpgio/2) * (klin * CLSIZE)) + ! 183: rp->p_slptime - (rp->p_nice-NZERO)*8; ! 184: if (rppri > outpri) { ! 185: if (rp->p_poip) ! 186: continue; ! 187: if (rp->p_textp && rp->p_textp->x_poip) ! 188: continue; ! 189: p = rp; ! 190: outpri = rppri; ! 191: } ! 192: } ! 193: continue; ! 194: ! 195: case SSLEEP: ! 196: case SSTOP: ! 197: if ((freemem < desfree || rp->p_rssize == 0) && ! 198: rp->p_slptime > maxslp && ! 199: (!rp->p_textp || (rp->p_textp->x_flag&XLOCK)==0) && ! 200: swappable(rp)) { ! 201: /* ! 202: * Kick out deadwood. ! 203: */ ! 204: (void) spl6(); ! 205: rp->p_flag &= ~SLOAD; ! 206: if (rp->p_stat == SRUN) ! 207: remrq(rp); ! 208: (void) spl0(); ! 209: (void) swapout(rp, rp->p_dsize, rp->p_ssize); ! 210: goto loop; ! 211: } ! 212: continue; ! 213: } ! 214: } ! 215: ! 216: /* ! 217: * No one wants in, so nothing to do. ! 218: */ ! 219: if (outpri == -20000) { ! 220: (void) spl6(); ! 221: if (wantin) { ! 222: wantin = 0; ! 223: sleep((caddr_t)&lbolt, PSWP); ! 224: } else { ! 225: runout++; ! 226: sleep((caddr_t)&runout, PSWP); ! 227: } ! 228: (void) spl0(); ! 229: goto loop; ! 230: } ! 231: /* ! 232: * Decide how deserving this guy is. If he is deserving ! 233: * we will be willing to work harder to bring him in. ! 234: * Needs is an estimate of how much core he will need. ! 235: * If he has been out for a while, then we will ! 236: * bring him in with 1/2 the core he will need, otherwise ! 237: * we are conservative. ! 238: */ ! 239: deservin = 0; ! 240: divisor = 1; ! 241: if (outpri > maxslp/2) { ! 242: deservin = 1; ! 243: divisor = 2; ! 244: } ! 245: needs = p->p_swrss; ! 246: if (p->p_textp && p->p_textp->x_ccount == 0) ! 247: needs += p->p_textp->x_swrss; ! 248: needs = imin(needs, lotsfree); ! 249: if (freemem - deficit > needs / divisor) { ! 250: deficit += needs; ! 251: if (swapin(p)) ! 252: goto loop; ! 253: deficit -= imin(needs, deficit); ! 254: } ! 255: ! 256: hardswap: ! 257: /* ! 258: * Need resources (kernel map or memory), swap someone out. ! 259: * Select the nbig largest jobs, then the oldest of these ! 260: * is ``most likely to get booted.'' ! 261: */ ! 262: inp = p; ! 263: sleeper = 0; ! 264: if (nbig > MAXNBIG) ! 265: nbig = MAXNBIG; ! 266: if (nbig < 1) ! 267: nbig = 1; ! 268: biggot = 0; ! 269: bplist.bp_link = 0; ! 270: for (rp = proc; rp < procNPROC; rp++) { ! 271: if (rp->p_stat == 0 || !swappable(rp)) ! 272: continue; ! 273: if (rp->p_stat==SZOMB) ! 274: continue; ! 275: if (rp == inp) ! 276: continue; ! 277: if (rp->p_textp && rp->p_textp->x_flag&XLOCK) ! 278: continue; ! 279: if (rp->p_slptime > maxslp && ! 280: (rp->p_stat==SSLEEP&&rp->p_pri>PZERO||rp->p_stat==SSTOP)) { ! 281: if (sleeper < rp->p_slptime) { ! 282: p = rp; ! 283: sleeper = rp->p_slptime; ! 284: } ! 285: } else if (!sleeper && (rp->p_stat==SRUN||rp->p_stat==SSLEEP)) { ! 286: rppri = rp->p_rssize; ! 287: if (rp->p_textp) ! 288: rppri += rp->p_textp->x_rssize/rp->p_textp->x_ccount; ! 289: if (biggot < nbig) ! 290: nbp = &bigp[biggot++]; ! 291: else { ! 292: nbp = bplist.bp_link; ! 293: if (nbp->bp_pri > rppri) ! 294: continue; ! 295: bplist.bp_link = nbp->bp_link; ! 296: } ! 297: for (bp = &bplist; bp->bp_link; bp = bp->bp_link) ! 298: if (rppri < bp->bp_link->bp_pri) ! 299: break; ! 300: nbp->bp_link = bp->bp_link; ! 301: bp->bp_link = nbp; ! 302: nbp->bp_pri = rppri; ! 303: nbp->bp_proc = rp; ! 304: } ! 305: } ! 306: if (!sleeper) { ! 307: p = NULL; ! 308: inpri = -1000; ! 309: for (bp = bplist.bp_link; bp; bp = bp->bp_link) { ! 310: rp = bp->bp_proc; ! 311: rppri = rp->p_time+rp->p_nice-NZERO; ! 312: if (rppri >= inpri) { ! 313: p = rp; ! 314: inpri = rppri; ! 315: } ! 316: } ! 317: } ! 318: /* ! 319: * If we found a long-time sleeper, or we are desperate and ! 320: * found anyone to swap out, or if someone deserves to come ! 321: * in and we didn't find a sleeper, but found someone who ! 322: * has been in core for a reasonable length of time, then ! 323: * we kick the poor luser out. ! 324: */ ! 325: if (sleeper || desperate && p || deservin && inpri > maxslp) { ! 326: (void) spl6(); ! 327: p->p_flag &= ~SLOAD; ! 328: if (p->p_stat == SRUN) ! 329: remrq(p); ! 330: (void) spl0(); ! 331: if (desperate) { ! 332: /* ! 333: * Want to give this space to the rest of ! 334: * the processes in core so give them a chance ! 335: * by increasing the deficit. ! 336: */ ! 337: gives = p->p_rssize; ! 338: if (p->p_textp) ! 339: gives += p->p_textp->x_rssize / p->p_textp->x_ccount; ! 340: gives = imin(gives, lotsfree); ! 341: deficit += gives; ! 342: } else ! 343: gives = 0; /* someone else taketh away */ ! 344: if (swapout(p, p->p_dsize, p->p_ssize) == 0) ! 345: deficit -= imin(gives, deficit); ! 346: goto loop; ! 347: } ! 348: /* ! 349: * Want to swap someone in, but can't ! 350: * so wait on runin. ! 351: */ ! 352: (void) spl6(); ! 353: runin++; ! 354: sleep((caddr_t)&runin, PSWP); ! 355: (void) spl0(); ! 356: goto loop; ! 357: } ! 358: ! 359: vmmeter() ! 360: { ! 361: register unsigned *cp, *rp, *sp; ! 362: ! 363: deficit -= imin(deficit, ! 364: imax(deficit / 10, ((klin * CLSIZE) / 2) * maxpgio / 2)); ! 365: ave(avefree, freemem, 5); ! 366: ave(avefree30, freemem, 30); ! 367: /* v_pgin is maintained by clock.c */ ! 368: cp = &cnt.v_first; rp = &rate.v_first; sp = &sum.v_first; ! 369: while (cp <= &cnt.v_last) { ! 370: ave(*rp, *cp, 5); ! 371: *sp += *cp; ! 372: *cp = 0; ! 373: rp++, cp++, sp++; ! 374: } ! 375: if (time % 5 == 0) { /* every fifth time into vmmeter */ ! 376: vmtotal(); ! 377: rate.v_swpin = cnt.v_swpin; ! 378: sum.v_swpin += cnt.v_swpin; ! 379: cnt.v_swpin = 0; ! 380: rate.v_swpout = cnt.v_swpout; ! 381: sum.v_swpout += cnt.v_swpout; ! 382: cnt.v_swpout = 0; ! 383: } ! 384: if (avefree < minfree && runout || proc[SWAPPID].p_slptime > maxslp/2) { ! 385: runout = 0; ! 386: runin = 0; ! 387: wakeup((caddr_t)&runin); ! 388: wakeup((caddr_t)&runout); ! 389: } ! 390: /* ! 391: * jolt the pageout daemon, in case ! 392: * there are just-cleaned pages but plenty of memory ! 393: */ ! 394: if (bclnlist != NULL) ! 395: wakeup((caddr_t)&proc[PAGEPID]); ! 396: timeout(vmmeter, (caddr_t)0, HZ); ! 397: } ! 398: ! 399: #define PAGOPSEC 4 /* how often we are called per second */ ! 400: ! 401: vmpago() ! 402: { ! 403: register int vavail; ! 404: register int scanrate; ! 405: ! 406: timeout(vmpago, (caddr_t)0, HZ/PAGOPSEC); ! 407: /* ! 408: * Compute new rate for clock; if ! 409: * nonzero, restart clock. ! 410: * Rate ranges linearly from one rev per ! 411: * slowscan seconds when there is lotsfree memory ! 412: * available to one rev per fastscan seconds when ! 413: * there is no memory available. ! 414: */ ! 415: nscan = desscan = 0; ! 416: vavail = freemem - deficit; ! 417: if (vavail < 0) ! 418: vavail = 0; ! 419: if (freemem >= lotsfree) ! 420: return; ! 421: scanrate = (slowscan * vavail + fastscan * (lotsfree - vavail)) / nz(lotsfree); ! 422: desscan = (LOOPPAGES / CLSIZE) / nz(scanrate); ! 423: desscan /= PAGOPSEC; ! 424: wakeup((caddr_t)&proc[PAGEPID]); ! 425: } ! 426: ! 427: vmtotal() ! 428: { ! 429: register struct proc *p; ! 430: register struct text *xp; ! 431: int nrun = 0; ! 432: ! 433: total.t_vmtxt = 0; ! 434: total.t_avmtxt = 0; ! 435: total.t_rmtxt = 0; ! 436: total.t_armtxt = 0; ! 437: for (xp = text; xp < textNTEXT; xp++) ! 438: if (xp->x_iptr) { ! 439: total.t_vmtxt += xp->x_size; ! 440: total.t_rmtxt += xp->x_rssize; ! 441: for (p = xp->x_caddr; p; p = p->p_xlink) ! 442: switch (p->p_stat) { ! 443: ! 444: case SSTOP: ! 445: case SSLEEP: ! 446: if (p->p_slptime >= maxslp) ! 447: continue; ! 448: /* fall into... */ ! 449: ! 450: case SRUN: ! 451: case SIDL: ! 452: total.t_avmtxt += xp->x_size; ! 453: total.t_armtxt += xp->x_rssize; ! 454: goto next; ! 455: } ! 456: next: ! 457: ; ! 458: } ! 459: total.t_vm = 0; ! 460: total.t_avm = 0; ! 461: total.t_rm = 0; ! 462: total.t_arm = 0; ! 463: total.t_rq = 0; ! 464: total.t_dw = 0; ! 465: total.t_pw = 0; ! 466: total.t_sl = 0; ! 467: total.t_sw = 0; ! 468: for (p = proc; p < procNPROC; p++) { ! 469: if (p->p_stat && (p->p_flag & SSYS) == 0) { ! 470: total.t_vm += p->p_dsize + p->p_ssize; ! 471: total.t_rm += p->p_rssize; ! 472: switch (p->p_stat) { ! 473: ! 474: case SSLEEP: ! 475: case SSTOP: ! 476: if (p->p_pri <= PZERO) ! 477: nrun++; ! 478: if (p->p_flag & SPAGE) ! 479: total.t_pw++; ! 480: else if (p->p_flag & SLOAD) { ! 481: if (p->p_pri <= PZERO) ! 482: total.t_dw++; ! 483: else if (p->p_slptime < maxslp) ! 484: total.t_sl++; ! 485: } else if (p->p_slptime < maxslp) ! 486: total.t_sw++; ! 487: if (p->p_slptime < maxslp) ! 488: goto active; ! 489: break; ! 490: ! 491: case SRUN: ! 492: case SIDL: ! 493: nrun++; ! 494: if (p->p_flag & SLOAD) ! 495: total.t_rq++; ! 496: else ! 497: total.t_sw++; ! 498: active: ! 499: total.t_avm += p->p_dsize + p->p_ssize; ! 500: total.t_arm += p->p_rssize; ! 501: break; ! 502: } ! 503: } ! 504: } ! 505: total.t_vm += total.t_vmtxt; ! 506: total.t_avm += total.t_avmtxt; ! 507: total.t_rm += total.t_rmtxt; ! 508: total.t_arm += total.t_armtxt; ! 509: total.t_free = avefree; ! 510: loadav(avenrun, nrun); ! 511: } ! 512: ! 513: /* ! 514: * Constants for averages over 1, 5, and 15 minutes ! 515: * when sampling at 5 second intervals. ! 516: */ ! 517: double cexp[3] = { ! 518: 0.9200444146293232, /* exp(-1/12) */ ! 519: 0.9834714538216174, /* exp(-1/60) */ ! 520: 0.9944598480048967, /* exp(-1/180) */ ! 521: }; ! 522: ! 523: /* ! 524: * Compute a tenex style load average of a quantity on ! 525: * 1, 5 and 15 minute intervals. ! 526: */ ! 527: loadav(avg, n) ! 528: register double *avg; ! 529: int n; ! 530: { ! 531: register int i; ! 532: ! 533: for (i = 0; i < 3; i++) ! 534: avg[i] = cexp[i] * avg[i] + n * (1.0 - cexp[i]); ! 535: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.