1 /* vm_meter.c 3.5 07/11/80 */ 2 3 #include "../h/param.h" 4 #include "../h/systm.h" 5 #include "../h/seg.h" 6 #include "../h/dir.h" 7 #include "../h/user.h" 8 #include "../h/proc.h" 9 #include "../h/text.h" 10 #include "../h/vm.h" 11 #include "../h/cmap.h" 12 13 int maxpgio = MAXPGIO; 14 int maxslp = MAXSLP; 15 int minfree = MINFREE; 16 int desfree = DESFREE; 17 int lotsfree = 0; /* set to LOTSFREE in main unless adbed */ 18 int saferss = SAFERSS; 19 int slowscan = SLOWSCAN; 20 int fastscan = FASTSCAN; 21 int klin = KLIN; 22 int klout = KLOUT; 23 int multprog = -1; /* so we don't count process 2 */ 24 25 double avenrun[3]; /* load average, of runnable procs */ 26 27 /* 28 * The main loop of the scheduling (swapping) process. 29 * 30 * The basic idea is: 31 * see if anyone wants to be swapped in; 32 * swap out processes until there is room; 33 * swap him in; 34 * repeat. 35 * If the paging rate is too high, or the average free memory 36 * is very low, then we do not consider swapping anyone in, 37 * but rather look for someone to swap out. 38 * 39 * The runout flag is set whenever someone is swapped out. 40 * Sched sleeps on it awaiting work. 41 * 42 * Sched sleeps on runin whenever it cannot find enough 43 * core (by swapping out or otherwise) to fit the 44 * selected swapped process. It is awakened when the 45 * core situation changes and in any case once per second. 46 * 47 * sched DOESN'T ACCOUNT FOR PAGE TABLE SIZE IN CALCULATIONS. 48 */ 49 50 #define swappable(p) \ 51 (((p)->p_flag&(SSYS|SLOCK|SULOCK|SLOAD|SPAGE|SKEEP|SWEXIT|SPHYSIO))==SLOAD) 52 53 /* insure non-zero */ 54 #define nz(x) (x != 0 ? x : 1) 55 56 #define NBIG 4 57 #define MAXNBIG 10 58 int nbig = NBIG; 59 60 struct bigp { 61 struct proc *bp_proc; 62 int bp_pri; 63 struct bigp *bp_link; 64 } bigp[MAXNBIG], bplist; 65 66 sched() 67 { 68 register struct proc *rp, *p, *inp; 69 int outpri, inpri, rppri; 70 int sleeper, desparate, deservin, needs, divisor; 71 register struct bigp *bp, *nbp; 72 int biggot, gives; 73 74 /* 75 * Check if paging rate is too high, or average of 76 * free list very low and if so, adjust multiprogramming 77 * load by swapping someone out. 78 * 79 * Avoid glitches: don't hard swap the only process, 80 * and don't swap based on paging rate if there is a reasonable 81 * amount of free memory. 82 */ 83 loop: 84 (void) spl6(); 85 deservin = 0; 86 sleeper = 0; 87 p = 0; 88 if (kmapwnt || (multprog > 1 && avefree < desfree && 89 (rate.v_pgin + rate.v_pgout > maxpgio || avefree < minfree))) { 90 desparate = 1; 91 goto hardswap; 92 } 93 desparate = 0; 94 /* 95 * Not desparate for core, 96 * look for someone who deserves to be brought in. 97 */ 98 outpri = -20000; 99 for (rp = &proc[0]; rp < &proc[NPROC]; rp++) switch(rp->p_stat) { 100 101 case SRUN: 102 if ((rp->p_flag&SLOAD) == 0) { 103 rppri = rp->p_time - rp->p_swrss / nz((maxpgio/2) * CLSIZE) + 104 rp->p_slptime - (rp->p_nice-NZERO)*8; 105 if (rppri > outpri) { 106 if (rp->p_poip) 107 continue; 108 if (rp->p_textp && rp->p_textp->x_poip) 109 continue; 110 p = rp; 111 outpri = rppri; 112 } 113 } 114 continue; 115 116 case SSLEEP: 117 case SSTOP: 118 if ((freemem < desfree || rp->p_rssize == 0) && 119 rp->p_slptime > maxslp && 120 (!rp->p_textp || (rp->p_textp->x_flag&XLOCK)==0) && 121 swappable(rp)) { 122 /* 123 * Kick out deadwood. 124 * FOLLOWING 3 LINES MUST BE AT spl6(). 125 */ 126 rp->p_flag &= ~SLOAD; 127 if (rp->p_stat == SRUN) 128 remrq(rp); 129 (void) swapout(rp, rp->p_dsize, rp->p_ssize); 130 goto loop; 131 } 132 continue; 133 } 134 135 /* 136 * No one wants in, so nothing to do. 137 */ 138 if (outpri == -20000) { 139 runout++; 140 sleep((caddr_t)&runout, PSWP); 141 goto loop; 142 } 143 (void) spl0(); 144 /* 145 * Decide how deserving this guy is. If he is deserving 146 * we will be willing to work harder to bring him in. 147 * Needs is an estimate of how much core he will need. 148 * If he has been out for a while, then we will 149 * bring him in with 1/2 the core he will need, otherwise 150 * we are conservative. 151 */ 152 deservin = 0; 153 divisor = 1; 154 if (outpri > maxslp/2) { 155 deservin = 1; 156 divisor = 2; 157 } 158 needs = p->p_swrss; 159 if (p->p_textp && p->p_textp->x_ccount == 0) 160 needs += p->p_textp->x_swrss; 161 if (freemem - deficit > needs / divisor) { 162 deficit += needs; 163 if (swapin(p)) 164 goto loop; 165 deficit -= imin(needs, deficit); 166 } 167 168 hardswap: 169 /* 170 * Need resources (kernel map or memory), swap someone out. 171 * Select the nbig largest jobs, then the oldest of these 172 * is ``most likely to get booted.'' 173 */ 174 (void) spl6(); 175 inp = p; 176 sleeper = 0; 177 if (nbig > MAXNBIG) 178 nbig = MAXNBIG; 179 if (nbig < 1) 180 nbig = 1; 181 biggot = 0; 182 bplist.bp_link = 0; 183 for (rp = &proc[0]; rp < &proc[NPROC]; rp++) { 184 if (!swappable(rp)) 185 continue; 186 if (rp->p_stat==SZOMB) 187 continue; 188 if (rp == inp) 189 continue; 190 if (rp->p_textp && rp->p_textp->x_flag&XLOCK) 191 continue; 192 if (rp->p_slptime > maxslp && 193 (rp->p_stat==SSLEEP&&rp->p_pri>PZERO||rp->p_stat==SSTOP)) { 194 if (sleeper < rp->p_slptime) { 195 p = rp; 196 sleeper = rp->p_slptime; 197 } 198 } else if (!sleeper && (rp->p_stat==SRUN||rp->p_stat==SSLEEP)) { 199 rppri = rp->p_rssize; 200 if (rp->p_textp) 201 rppri += rp->p_textp->x_rssize/rp->p_textp->x_ccount; 202 if (biggot < nbig) 203 nbp = &bigp[biggot++]; 204 else { 205 nbp = bplist.bp_link; 206 if (nbp->bp_pri > rppri) 207 continue; 208 bplist.bp_link = nbp->bp_link; 209 } 210 for (bp = &bplist; bp->bp_link; bp = bp->bp_link) 211 if (rppri < bp->bp_link->bp_pri) 212 break; 213 nbp->bp_link = bp->bp_link; 214 bp->bp_link = nbp; 215 nbp->bp_pri = rppri; 216 nbp->bp_proc = rp; 217 } 218 } 219 if (!sleeper) { 220 p = NULL; 221 inpri = -1000; 222 for (bp = bplist.bp_link; bp; bp = bp->bp_link) { 223 rp = bp->bp_proc; 224 rppri = rp->p_time+rp->p_nice-NZERO; 225 if (rppri >= inpri) { 226 p = rp; 227 inpri = rppri; 228 } 229 } 230 } 231 /* 232 * If we found a long-time sleeper, or we are desparate and 233 * found anyone to swap out, or if someone deserves to come 234 * in and we didn't find a sleeper, but found someone who 235 * has been in core for a reasonable length of time, then 236 * we kick the poor luser out. 237 */ 238 if (sleeper || desparate && p || deservin && inpri > maxslp) { 239 p->p_flag &= ~SLOAD; 240 if (p->p_stat == SRUN) 241 remrq(p); 242 if (desparate) { 243 /* 244 * Want to give this space to the rest of 245 * the processes in core so give them a chance 246 * by increasing the deficit. 247 */ 248 gives = p->p_rssize; 249 if (p->p_textp) 250 gives += p->p_textp->x_rssize / p->p_textp->x_ccount; 251 deficit += gives; 252 } else 253 gives = 0; /* someone else taketh away */ 254 if (swapout(p, p->p_dsize, p->p_ssize) == 0) 255 deficit -= imin(gives, deficit); 256 goto loop; 257 } 258 /* 259 * Want to swap someone in, but can't 260 * so wait on runin. 261 */ 262 (void) spl6(); 263 runin++; 264 sleep((caddr_t)&runin, PSWP); 265 goto loop; 266 } 267 268 vmmeter() 269 { 270 register unsigned *cp, *rp, *sp; 271 272 deficit -= imin(deficit, imax(deficit / 10, maxpgio / 2)); 273 ave(avefree, freemem, 5); 274 /* v_pgin is maintained by clock.c */ 275 cp = &cnt.v_first; rp = &rate.v_first; sp = &sum.v_first; 276 while (cp <= &cnt.v_last) { 277 ave(*rp, *cp, 5); 278 *sp += *cp; 279 *cp = 0; 280 rp++, cp++, sp++; 281 } 282 if (time % 5 == 0) { 283 vmtotal(); 284 rate.v_swpin = cnt.v_swpin; 285 sum.v_swpin += cnt.v_swpin; 286 cnt.v_swpin = 0; 287 rate.v_swpout = cnt.v_swpout; 288 sum.v_swpout += cnt.v_swpout; 289 cnt.v_swpout = 0; 290 } 291 if (avefree < minfree && runout || proc[0].p_slptime > maxslp/2) { 292 runout = 0; 293 runin = 0; 294 wakeup((caddr_t)&runin); 295 wakeup((caddr_t)&runout); 296 } 297 } 298 299 vmpago() 300 { 301 register int vavail; 302 register int scanrate; 303 304 /* 305 * Compute new rate for clock; if 306 * nonzero, restart clock. 307 * Rate ranges linearly from one rev per 308 * slowscan seconds when there is lotsfree memory 309 * available to one rev per fastscan seconds when 310 * there is no memory available. 311 */ 312 nscan = desscan = 0; 313 vavail = freemem - deficit; 314 if (vavail < 0) 315 vavail = 0; 316 if (freemem >= lotsfree) 317 return; 318 scanrate = (slowscan * vavail + fastscan * (lotsfree - vavail)) / nz(lotsfree); 319 desscan = LOOPSIZ / nz(scanrate); 320 /* 321 * DIVIDE BY 4 TO ACCOUNT FOR RUNNING 4* A SECOND (see clock.c) 322 */ 323 desscan /= 4; 324 wakeup((caddr_t)&proc[2]); 325 } 326 327 vmtotal() 328 { 329 register struct proc *p; 330 register struct text *xp; 331 int nrun = 0; 332 333 total.t_vmtxt = 0; 334 total.t_avmtxt = 0; 335 total.t_rmtxt = 0; 336 total.t_armtxt = 0; 337 for (xp = &text[0]; xp < &text[NTEXT]; xp++) 338 if (xp->x_iptr) { 339 total.t_vmtxt += xp->x_size; 340 total.t_rmtxt += xp->x_rssize; 341 for (p = xp->x_caddr; p; p = p->p_xlink) 342 switch (p->p_stat) { 343 344 case SSTOP: 345 case SSLEEP: 346 if (p->p_slptime >= maxslp) 347 continue; 348 /* fall into... */ 349 350 case SRUN: 351 case SIDL: 352 total.t_avmtxt += xp->x_size; 353 total.t_armtxt += xp->x_rssize; 354 goto next; 355 } 356 next: 357 ; 358 } 359 total.t_vm = 0; 360 total.t_avm = 0; 361 total.t_rm = 0; 362 total.t_arm = 0; 363 total.t_rq = 0; 364 total.t_dw = 0; 365 total.t_pw = 0; 366 total.t_sl = 0; 367 total.t_sw = 0; 368 for (p = &proc[0]; p < &proc[NPROC]; p++) { 369 if (p->p_flag & SSYS) 370 continue; 371 if (p->p_stat) { 372 total.t_vm += p->p_dsize + p->p_ssize; 373 total.t_rm += p->p_rssize; 374 switch (p->p_stat) { 375 376 case SSLEEP: 377 case SSTOP: 378 if (p->p_pri <= PZERO) 379 nrun++; 380 if (p->p_flag & SPAGE) 381 total.t_pw++; 382 else if (p->p_flag & SLOAD) { 383 if (p->p_pri <= PZERO) 384 total.t_dw++; 385 else if (p->p_slptime < maxslp) 386 total.t_sl++; 387 } else if (p->p_slptime < maxslp) 388 total.t_sw++; 389 if (p->p_slptime < maxslp) 390 goto active; 391 break; 392 393 case SRUN: 394 case SIDL: 395 nrun++; 396 if (p->p_flag & SLOAD) 397 total.t_rq++; 398 else 399 total.t_sw++; 400 active: 401 total.t_avm += p->p_dsize + p->p_ssize; 402 total.t_arm += p->p_rssize; 403 break; 404 } 405 } 406 } 407 total.t_vm += total.t_vmtxt; 408 total.t_avm += total.t_avmtxt; 409 total.t_rm += total.t_rmtxt; 410 total.t_arm += total.t_armtxt; 411 total.t_free = avefree; 412 loadav(avenrun, nrun); 413 } 414 415 /* 416 * Constants for averages over 1, 5, and 15 minutes 417 * when sampling at 5 second intervals. 418 */ 419 double cexp[3] = { 420 0.9200444146293232, /* exp(-1/12) */ 421 0.9834714538216174, /* exp(-1/60) */ 422 0.9944598480048967, /* exp(-1/180) */ 423 }; 424 425 /* 426 * Compute a tenex style load average of a quantity on 427 * 1, 5 and 15 minute intervals. 428 */ 429 loadav(avg, n) 430 register double *avg; 431 int n; 432 { 433 register int i; 434 435 for (i = 0; i < 3; i++) 436 avg[i] = cexp[i] * avg[i] + n * (1.0 - cexp[i]); 437 } 438