spelling of desperate
[unix-history] / usr / src / sys / vm / vm_meter.c
CommitLineData
97afa637 1/* vm_meter.c 3.6 %G% */
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"
12
13int maxpgio = MAXPGIO;
14int maxslp = MAXSLP;
15int minfree = MINFREE;
16int desfree = DESFREE;
17int lotsfree = 0; /* set to LOTSFREE in main unless adbed */
18int saferss = SAFERSS;
19int slowscan = SLOWSCAN;
20int fastscan = FASTSCAN;
21int klin = KLIN;
22int klout = KLOUT;
23int multprog = -1; /* so we don't count process 2 */
24
25double 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
58int nbig = NBIG;
59
60struct bigp {
61 struct proc *bp_proc;
62 int bp_pri;
63 struct bigp *bp_link;
64} bigp[MAXNBIG], bplist;
65
66sched()
67{
68 register struct proc *rp, *p, *inp;
69 int outpri, inpri, rppri;
97afa637 70 int sleeper, desperate, deservin, needs, divisor;
e3bf9f41
BJ
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 */
83loop:
e650efcf 84 (void) spl6();
e3bf9f41
BJ
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))) {
97afa637 90 desperate = 1;
e3bf9f41
BJ
91 goto hardswap;
92 }
97afa637 93 desperate = 0;
e3bf9f41 94 /*
97afa637 95 * Not desperate for core,
e3bf9f41
BJ
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) {
293c7069
BJ
103 rppri = rp->p_time - rp->p_swrss / nz((maxpgio/2) * CLSIZE) +
104 rp->p_slptime - (rp->p_nice-NZERO)*8;
e3bf9f41
BJ
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);
e650efcf 129 (void) swapout(rp, rp->p_dsize, rp->p_ssize);
e3bf9f41
BJ
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 }
e650efcf 143 (void) spl0();
e3bf9f41
BJ
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
168hardswap:
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 */
e650efcf 174 (void) spl6();
e3bf9f41
BJ
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 &&
89b899a0 193 (rp->p_stat==SSLEEP&&rp->p_pri>PZERO||rp->p_stat==SSTOP)) {
e3bf9f41
BJ
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)
293c7069 201 rppri += rp->p_textp->x_rssize/rp->p_textp->x_ccount;
e3bf9f41
BJ
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 /*
97afa637 232 * If we found a long-time sleeper, or we are desperate and
e3bf9f41
BJ
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 */
97afa637 238 if (sleeper || desperate && p || deservin && inpri > maxslp) {
e3bf9f41
BJ
239 p->p_flag &= ~SLOAD;
240 if (p->p_stat == SRUN)
241 remrq(p);
97afa637 242 if (desperate) {
e3bf9f41
BJ
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 */
e650efcf 262 (void) spl6();
e3bf9f41
BJ
263 runin++;
264 sleep((caddr_t)&runin, PSWP);
265 goto loop;
266}
267
268vmmeter()
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
299vmpago()
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
327vmtotal()
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 }
356next:
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:
89b899a0 378 if (p->p_pri <= PZERO)
e3bf9f41
BJ
379 nrun++;
380 if (p->p_flag & SPAGE)
381 total.t_pw++;
382 else if (p->p_flag & SLOAD) {
89b899a0 383 if (p->p_pri <= PZERO)
e3bf9f41
BJ
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++;
400active:
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 */
419double 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 */
429loadav(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}