|
|
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.