* Copyright (c) 1982, 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
* @(#)kern_synch.c 7.7 (Berkeley) %G%
#include "machine/mtpr.h"
* Force switch among equal priority processes every 100ms.
timeout(roundrobin
, (caddr_t
)0, hz
/ 10);
* constants for digital decay and forget
* 90% of (p_cpu) usage in 5*loadav time
* 95% of (p_pctcpu) usage in 60 seconds (load insensitive)
* Note that, as ps(1) mentions, this can let percentages
* total over 100% (I've seen 137.9% for 3 processes).
* Note that hardclock updates p_cpu and p_cpticks independently.
* We wish to decay away 90% of p_cpu in (5 * loadavg) seconds.
* That is, the system wants to compute a value of decay such
* that the following for loop:
* for (i = 0; i < (5 * loadavg); i++)
* for all values of loadavg:
* Mathematically this loop can be expressed by saying:
* decay ** (5 * loadavg) ~= .1
* The system computes decay as:
* decay = (2 * loadavg) / (2 * loadavg + 1)
* We wish to prove that the system's computation of decay
* will always fulfill the equation:
* decay ** (5 * loadavg) ~= .1
* We now need to prove two things:
* 1) Given factor ** (5 * loadavg) ~= .1, prove factor == b/(b+1)
* 2) Given b/(b+1) ** power ~= .1, prove power == (5 * loadavg)
* For x close to zero, exp(x) =~ 1 + x, since
* exp(x) = 0! + x**1/1! + x**2/2! + ... .
* therefore exp(-1/b) =~ 1 - (1/b) = (b-1)/b.
* For x close to zero, ln(1+x) =~ x, since
* ln(1+x) = x - x**2/2 + x**3/3 - ... -1 < x < 1
* therefore ln(b/(b+1)) = ln(1 - 1/(b+1)) =~ -1/(b+1).
* Solve (factor)**(power) =~ .1 given power (5*loadav):
* ln(factor) =~ (-2.30/5*loadav), or
* factor =~ exp(-1/((5/2.30)*loadav) =~ exp(-1/(2*loadav)) =
* exp(-1/b) =~ (b-1)/b =~ b/(b+1). QED
* Solve (factor)**(power) =~ .1 given factor == (b/(b+1)):
* power*ln(b/(b+1)) =~ -2.30, or
* power =~ 2.3 * (b + 1) = 4.6*loadav + 2.3 =~ 5*loadav. QED
* Actual power values for the implemented algorithm are as follows:
* power: 5.68 10.32 14.94 19.55
#define filter(loadav) ((2 * (loadav)) / (2 * (loadav) + 1))
double ccpu
= 0.95122942450071400909; /* exp(-1/20) */
* Recompute process priorities, once a second
register double ccpu1
= (1.0 - ccpu
) / (double)hz
;
float scale
= filter(avenrun
[0]);
for (p
= allproc
; p
!= NULL
; p
= p
->p_nxt
) {
if (p
->p_stat
==SSLEEP
|| p
->p_stat
==SSTOP
)
* If the process has slept the entire second,
* stop recalculating its priority until it wakes up.
* p_pctcpu is only for ps.
p
->p_pctcpu
= ccpu
* p
->p_pctcpu
+ ccpu1
* p
->p_cpticks
;
a
= (int) (scale
* (p
->p_cpu
& 0377)) + p
->p_nice
;
s
= splhigh(); /* prevent state changes */
if ((p
!= u
.u_procp
|| noproc
) &&
(p
->p_pri
/ PPQ
) != (p
->p_usrpri
/ PPQ
)) {
wakeup((caddr_t
)&proc
[2]);
timeout(schedcpu
, (caddr_t
)0, hz
);
* Recalculate the priority of a process after it has slept for a while.
register int a
= p
->p_cpu
& 0377;
float scale
= filter(avenrun
[0]);
p
->p_slptime
--; /* the first time was done in schedcpu */
while (a
&& --p
->p_slptime
)
a
= (int) (scale
* a
) /* + p->p_nice */;
#define SQSIZE 0100 /* Must be power of 2 */
#define HASH(x) (( (int) x >> 5) & (SQSIZE-1))
* Give up the processor till a wakeup occurs
* on chan, at which time the process
* enters the scheduling queue at priority pri.
* The most important effect of pri is that when
* pri<=PZERO a signal cannot disturb the sleep;
* if pri>PZERO signals will be processed.
* Callers of this routine must be prepared for
* premature return, and check that the reason for
* sleeping has gone away.
register struct proc
*rp
;
register struct slpque
*qp
;
* After a panic, or during autoconfiguration,
* just give interrupts a chance, then just return;
* don't run any other procs or panic below,
* in case this is the idle process and already asleep.
* The splnet should be spl0 if the network was being used
* by the filesystem, but for now avoid network interrupts
* that might cause another panic.
if (chan
==0 || rp
->p_stat
!= SRUN
|| rp
->p_rlink
)
qp
= &slpque
[HASH(chan
)];
*(qp
->sq_tailp
= &rp
->p_link
) = 0;
* If we stop in issig(), wakeup may already have happened
* when we return (rp->p_wchan will then be 0).
* If priority was low (>PZERO) and
* there has been a signal, execute non-local goto through
* u.u_qsave, aborting the system call in progress (see trap.c)
* Remove a process from its wait queue
register struct slpque
*qp
;
register struct proc
**hp
;
hp
= &(qp
= &slpque
[HASH(p
->p_wchan
)])->sq_head
;
if (qp
->sq_tailp
== &p
->p_link
)
* Wake up all processes sleeping on chan.
register struct slpque
*qp
;
register struct proc
*p
, **q
;
qp
= &slpque
[HASH(chan
)];
for (q
= &qp
->sq_head
; p
= *q
; ) {
if (p
->p_rlink
|| p
->p_stat
!= SSLEEP
&& p
->p_stat
!= SSTOP
)
if (qp
->sq_tailp
== &p
->p_link
)
if (p
->p_stat
== SSLEEP
) {
/* OPTIMIZED INLINE EXPANSION OF setrun(p) */
* Since curpri is a usrpri,
* p->p_pri is always better than curpri.
if ((p
->p_flag
&SLOAD
) == 0) {
wakeup((caddr_t
)&runout
);
/* END INLINE EXPANSION */
* Initialize the (doubly-linked) run queues
for (i
= 0; i
< NQS
; i
++)
qs
[i
].ph_link
= qs
[i
].ph_rlink
= (struct proc
*)&qs
[i
];
* Set the process running;
* arrange for it to be swapped in if necessary.
unsleep(p
); /* e.g. when sending signals */
if ((p
->p_flag
&SLOAD
) == 0) {
wakeup((caddr_t
)&runout
);
* The rescheduling flag (runrun)
* is set if the priority is better
* than the currently running process.
register struct proc
*pp
;
p
= (pp
->p_cpu
& 0377)/4;
p
+= PUSER
+ 2 * pp
->p_nice
;
if (pp
->p_rssize
> pp
->p_maxrss
&& freemem
< desfree
)
p
+= 2*4; /* effectively, nice(4) */