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