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