|
|
1.1 root 1: /*
2: * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution is only permitted until one year after the first shipment
6: * of 4.4BSD by the Regents. Otherwise, redistribution and use in source and
7: * binary forms are permitted provided that: (1) source distributions retain
8: * this entire copyright notice and comment, and (2) distributions including
9: * binaries display the following acknowledgement: This product includes
10: * software developed by the University of California, Berkeley and its
11: * contributors'' in the documentation or other materials provided with the
12: * distribution and in all advertising materials mentioning features or use
13: * of this software. Neither the name of the University nor the names of
14: * its contributors may be used to endorse or promote products derived from
15: * this software without specific prior written permission.
16: * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
17: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
18: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19: *
20: * @(#)vm_sched.c 7.9 (Berkeley) 6/28/90
21: */
22:
23: #include "param.h"
24: #include "systm.h"
25: #include "user.h"
26: #include "proc.h"
27: #include "text.h"
28: #include "vm.h"
29: #include "kernel.h"
30:
31: int maxslp = MAXSLP;
32: int saferss = SAFERSS;
33:
34: /*
35: * The following parameters control operation of the page replacement
36: * algorithm. They are initialized to 0, and then computed at boot time
37: * based on the size of the system. If they are patched non-zero in
38: * a loaded vmunix they are left alone and may thus be changed per system
39: * using adb on the loaded system.
40: */
41: int maxpgio = 0;
42: int minfree = 0;
43: int desfree = 0;
44: int lotsfree = 0;
45: int slowscan = 0;
46: int fastscan = 0;
47: int klin = KLIN;
48: int klseql = KLSEQL;
49: int klsdist = KLSDIST;
50: int kltxt = KLTXT;
51: int klout = KLOUT;
52: int multprog = -1; /* so we don't count process 2 */
53:
54: fixpt_t averunnable[3]; /* load average, of runnable procs */
55:
56: /*
57: * The main loop of the scheduling (swapping) process.
58: *
59: * The basic idea is:
60: * see if anyone wants to be swapped in;
61: * swap out processes until there is room;
62: * swap him in;
63: * repeat.
64: * If the paging rate is too high, or the average free memory
65: * is very low, then we do not consider swapping anyone in,
66: * but rather look for someone to swap out.
67: *
68: * The runout flag is set whenever someone is swapped out.
69: * Sched sleeps on it awaiting work.
70: *
71: * Sched sleeps on runin whenever it cannot find enough
72: * core (by swapping out or otherwise) to fit the
73: * selected swapped process. It is awakened when the
74: * core situation changes and in any case once per second.
75: *
76: * sched DOESN'T ACCOUNT FOR PAGE TABLE SIZE IN CALCULATIONS.
77: */
78:
79: #define swappable(p) \
80: (((p)->p_flag&(SSYS|SLOCK|SULOCK|SLOAD|SPAGE|SKEEP|SWEXIT|SPHYSIO))==SLOAD)
81:
82: /* insure non-zero */
83: #define nz(x) (x != 0 ? x : 1)
84:
85: #define NBIG 4
86: #define MAXNBIG 10
87: int nbig = NBIG;
88:
89: struct bigp {
90: struct proc *bp_proc;
91: int bp_pri;
92: struct bigp *bp_link;
93: } bigp[MAXNBIG], bplist;
94:
95: sched()
96: {
97: register struct proc *rp, *p, *inp;
98: int outpri, inpri, rppri;
99: int sleeper, desperate, deservin, needs, divisor;
100: register struct bigp *bp, *nbp;
101: int biggot, gives;
102:
103: loop:
104: wantin = 0;
105: deservin = 0;
106: sleeper = 0;
107: p = 0;
108: /*
109: * See if paging system is overloaded; if so swap someone out.
110: * Conditions for hard outswap are:
111: * if need kernel map (mix it up).
112: * or
113: * 1. if there are at least 2 runnable processes (on the average)
114: * and 2. the paging rate is excessive or memory is now VERY low.
115: * and 3. the short (5-second) and longer (30-second) average
116: * memory is less than desirable.
117: */
118: if (kmapwnt ||
119: (averunnable[0] >= 2 * FSCALE &&
120: imax(avefree, avefree30) < desfree &&
121: (rate.v_pgin + rate.v_pgout > maxpgio || avefree < minfree))) {
122: desperate = 1;
123: goto hardswap;
124: }
125: desperate = 0;
126: /*
127: * Not desperate for core,
128: * look for someone who deserves to be brought in.
129: */
130: outpri = -20000;
131: for (rp = allproc; rp != NULL; rp = rp->p_nxt) switch(rp->p_stat) {
132:
133: case SRUN:
134: if ((rp->p_flag&SLOAD) == 0) {
135: rppri = rp->p_time -
136: rp->p_swrss / nz((maxpgio/2) * (klin * CLSIZE)) +
137: rp->p_slptime - (rp->p_nice-NZERO)*8;
138: if (rppri > outpri) {
139: if (rp->p_poip)
140: continue;
141: if (rp->p_textp && rp->p_textp->x_poip)
142: continue;
143: p = rp;
144: outpri = rppri;
145: }
146: }
147: continue;
148:
149: case SSLEEP:
150: case SSTOP:
151: if ((freemem < desfree || rp->p_rssize == 0) &&
152: rp->p_slptime > maxslp &&
153: (!rp->p_textp || (rp->p_textp->x_flag&XLOCK)==0) &&
154: swappable(rp)) {
155: /*
156: * Kick out deadwood.
157: */
158: rp->p_flag &= ~SLOAD;
159: (void) swapout(rp, rp->p_dsize, rp->p_mmsize, rp->p_ssize);
160: }
161: continue;
162: }
163:
164: /*
165: * If something came ready after we checked it,
166: * wantin will be set. Otherwise,
167: * no one wants in, so nothing to do.
168: */
169: if (outpri == -20000) {
170: (void) splhigh();
171: if (wantin == 0) {
172: runout++;
173: sleep((caddr_t)&runout, PSWP);
174: }
175: (void) spl0();
176: goto loop;
177: }
178: /*
179: * Decide how deserving this guy is. If he is deserving
180: * we will be willing to work harder to bring him in.
181: * Needs is an estimate of how much core he will need.
182: * If he has been out for a while, then we will
183: * bring him in with 1/2 the core he will need, otherwise
184: * we are conservative.
185: */
186: deservin = 0;
187: divisor = 1;
188: if (outpri > maxslp/2) {
189: deservin = 1;
190: divisor = 2;
191: }
192: needs = p->p_swrss;
193: if (p->p_textp && p->p_textp->x_ccount == 0)
194: needs += p->p_textp->x_swrss;
195: needs = imin(needs, lotsfree);
196: if (freemem - deficit > needs / divisor) {
197: deficit += needs;
198: if (swapin(p))
199: goto loop;
200: deficit -= imin(needs, deficit);
201: }
202:
203: hardswap:
204: /*
205: * Need resources (kernel map or memory), swap someone out.
206: * Select the nbig largest jobs, then the oldest of these
207: * is ``most likely to get booted.''
208: */
209: inp = p;
210: sleeper = 0;
211: if (nbig > MAXNBIG)
212: nbig = MAXNBIG;
213: if (nbig < 1)
214: nbig = 1;
215: biggot = 0;
216: bplist.bp_link = 0;
217: for (rp = allproc; rp != NULL; rp = rp->p_nxt) {
218: if (!swappable(rp))
219: continue;
220: if (rp == inp)
221: continue;
222: if (rp->p_textp && rp->p_textp->x_flag&XLOCK)
223: continue;
224: if (rp->p_slptime > maxslp &&
225: (rp->p_stat==SSLEEP&&rp->p_pri>PZERO||rp->p_stat==SSTOP)) {
226: if (sleeper < rp->p_slptime) {
227: p = rp;
228: sleeper = rp->p_slptime;
229: }
230: } else if (!sleeper && (rp->p_stat==SRUN||rp->p_stat==SSLEEP)) {
231: rppri = rp->p_rssize;
232: if (rp->p_textp)
233: rppri += rp->p_textp->x_rssize/rp->p_textp->x_ccount;
234: if (biggot < nbig)
235: nbp = &bigp[biggot++];
236: else {
237: nbp = bplist.bp_link;
238: if (nbp->bp_pri > rppri)
239: continue;
240: bplist.bp_link = nbp->bp_link;
241: }
242: for (bp = &bplist; bp->bp_link; bp = bp->bp_link)
243: if (rppri < bp->bp_link->bp_pri)
244: break;
245: nbp->bp_link = bp->bp_link;
246: bp->bp_link = nbp;
247: nbp->bp_pri = rppri;
248: nbp->bp_proc = rp;
249: }
250: }
251: if (!sleeper) {
252: p = NULL;
253: inpri = -1000;
254: for (bp = bplist.bp_link; bp; bp = bp->bp_link) {
255: rp = bp->bp_proc;
256: rppri = rp->p_time+rp->p_nice-NZERO;
257: if (rppri >= inpri) {
258: p = rp;
259: inpri = rppri;
260: }
261: }
262: }
263: /*
264: * If we found a long-time sleeper, or we are desperate and
265: * found anyone to swap out, or if someone deserves to come
266: * in and we didn't find a sleeper, but found someone who
267: * has been in core for a reasonable length of time, then
268: * we kick the poor luser out.
269: */
270: if (sleeper || desperate && p || deservin && inpri > maxslp) {
271: (void) splhigh();
272: p->p_flag &= ~SLOAD;
273: if (p->p_stat == SRUN)
274: remrq(p);
275: (void) spl0();
276: if (desperate) {
277: /*
278: * Want to give this space to the rest of
279: * the processes in core so give them a chance
280: * by increasing the deficit.
281: */
282: gives = p->p_rssize;
283: if (p->p_textp)
284: gives += p->p_textp->x_rssize / p->p_textp->x_ccount;
285: gives = imin(gives, lotsfree);
286: deficit += gives;
287: } else
288: gives = 0; /* someone else taketh away */
289: if (swapout(p, p->p_dsize, p->p_mmsize, p->p_ssize) == 0)
290: deficit -= imin(gives, deficit);
291: else
292: goto loop;
293: }
294: /*
295: * Want to swap someone in, but can't
296: * so wait on runin.
297: */
298: (void) splhigh();
299: runin++;
300: sleep((caddr_t)&runin, PSWP);
301: (void) spl0();
302: goto loop;
303: }
304:
305: vmmeter()
306: {
307: register unsigned *cp, *rp, *sp;
308:
309: deficit -= imin(deficit,
310: imax(deficit / 10, ((klin * CLSIZE) / 2) * maxpgio / 2));
311: ave(avefree, freemem, 5);
312: ave(avefree30, freemem, 30);
313: /* v_pgin is maintained by clock.c */
314: cp = &cnt.v_first; rp = &rate.v_first; sp = &sum.v_first;
315: while (cp <= &cnt.v_last) {
316: ave(*rp, *cp, 5);
317: *sp += *cp;
318: *cp = 0;
319: rp++, cp++, sp++;
320: }
321: if (time.tv_sec % 5 == 0) {
322: vmtotal();
323: rate.v_swpin = cnt.v_swpin;
324: sum.v_swpin += cnt.v_swpin;
325: cnt.v_swpin = 0;
326: rate.v_swpout = cnt.v_swpout;
327: sum.v_swpout += cnt.v_swpout;
328: cnt.v_swpout = 0;
329: }
330: if (avefree < minfree && runout || proc[0].p_slptime > maxslp/2) {
331: runout = 0;
332: runin = 0;
333: wakeup((caddr_t)&runin);
334: wakeup((caddr_t)&runout);
335: }
336: }
337:
338: /*
339: * Schedule rate for paging.
340: * Rate is linear interpolation between
341: * slowscan with lotsfree and fastscan when out of memory.
342: */
343: schedpaging()
344: {
345: register int vavail;
346:
347: nscan = desscan = 0;
348: vavail = freemem - deficit;
349: if (vavail < 0)
350: vavail = 0;
351: if (freemem < lotsfree) {
352: desscan = (slowscan * vavail + fastscan * (lotsfree - vavail)) /
353: nz(lotsfree) / RATETOSCHEDPAGING;
354: wakeup((caddr_t)&proc[2]);
355: }
356: timeout(schedpaging, (caddr_t)0, hz / RATETOSCHEDPAGING);
357: }
358:
359: vmtotal()
360: {
361: register struct proc *p;
362: register struct text *xp;
363: int nrun = 0;
364:
365: total.t_vmtxt = 0;
366: total.t_avmtxt = 0;
367: total.t_rmtxt = 0;
368: total.t_armtxt = 0;
369: for (xp = text; xp < textNTEXT; xp++)
370: if (xp->x_vptr) {
371: total.t_vmtxt += xp->x_size;
372: total.t_rmtxt += xp->x_rssize;
373: for (p = xp->x_caddr; p; p = p->p_xlink)
374: switch (p->p_stat) {
375:
376: case SSTOP:
377: case SSLEEP:
378: if (p->p_slptime >= maxslp)
379: continue;
380: /* fall into... */
381:
382: case SRUN:
383: case SIDL:
384: total.t_avmtxt += xp->x_size;
385: total.t_armtxt += xp->x_rssize;
386: goto next;
387: }
388: next:
389: ;
390: }
391: total.t_vm = 0;
392: total.t_avm = 0;
393: total.t_rm = 0;
394: total.t_arm = 0;
395: total.t_rq = 0;
396: total.t_dw = 0;
397: total.t_pw = 0;
398: total.t_sl = 0;
399: total.t_sw = 0;
400: for (p = allproc; p != NULL; p = p->p_nxt) {
401: if (p->p_flag & SSYS)
402: continue;
403: if (p->p_stat) {
404: if (p->p_stat != SZOMB) {
405: total.t_vm += p->p_dsize + p->p_ssize;
406: total.t_rm += p->p_rssize;
407: }
408: switch (p->p_stat) {
409:
410: case SSLEEP:
411: if (p->p_pri <= PZERO && p->p_slptime == 0)
412: nrun++;
413: /* fall through */
414: case SSTOP:
415: if (p->p_flag & SPAGE)
416: total.t_pw++;
417: else if (p->p_flag & SLOAD) {
418: if (p->p_pri <= PZERO)
419: total.t_dw++;
420: else if (p->p_slptime < maxslp)
421: total.t_sl++;
422: } else if (p->p_slptime < maxslp)
423: total.t_sw++;
424: if (p->p_slptime < maxslp)
425: goto active;
426: break;
427:
428: case SRUN:
429: case SIDL:
430: nrun++;
431: if (p->p_flag & SLOAD)
432: total.t_rq++;
433: else
434: total.t_sw++;
435: active:
436: total.t_avm += p->p_dsize + p->p_ssize;
437: total.t_arm += p->p_rssize;
438: break;
439: }
440: }
441: }
442: total.t_vm += total.t_vmtxt;
443: total.t_avm += total.t_avmtxt;
444: total.t_rm += total.t_rmtxt;
445: total.t_arm += total.t_armtxt;
446: total.t_free = avefree;
447: loadav(averunnable, nrun);
448: }
449:
450: /*
451: * Constants for averages over 1, 5, and 15 minutes
452: * when sampling at 5 second intervals.
453: */
454: fixpt_t cexp[3] = {
455: 0.9200444146293232 * FSCALE, /* exp(-1/12) */
456: 0.9834714538216174 * FSCALE, /* exp(-1/60) */
457: 0.9944598480048967 * FSCALE, /* exp(-1/180) */
458: };
459:
460: /*
461: * Compute a tenex style load average of a quantity on
462: * 1, 5 and 15 minute intervals.
463: */
464: loadav(avg, n)
465: register fixpt_t *avg;
466: int n;
467: {
468: register int i;
469:
470: for (i = 0; i < 3; i++)
471: avg[i] = (cexp[i] * avg[i] + n * FSCALE * (FSCALE - cexp[i]))
472: >> FSHIFT;
473: #if defined(COMPAT_43) && (defined(vax) || defined(tahoe))
474: for (i = 0; i < 3; i++)
475: avenrun[i] = (double) averunnable[i] / FSCALE;
476: #endif /* COMPAT_43 */
477: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.