Time slicing -- How does 4.3bsd do it?

Bret McKee mckee at hpfcdc.HP.COM
Thu Jan 19 03:06:44 AEST 1989


The BSD scheduler is a non-trivial animal.  The following description is 
actually for 4.2, but I believe it is little changed in 4.3.

Each process is assigned a priority between 0 and 127.  In the BSD
scheme lower numbers mean higher priority.  The scheduler maintains 32
queues, numbered 0 to 31.  (There are 31 queues instead of 127 for reasons
of efficiency) Each process is maintained on queue[priority/4].  At any 
instant in time the process with the highest priority (lowest number) is 
the running process (for these purposes all processes on the same queue 
are considered to have the same priority).

These queues are divided into two distinct groups: processes on queues 0-11 are 
said to be executing at kernel priority while those on queues 12-31 are 
executing at user priority.  The major differences between the two priority
levels is that kernel priority processes are never preempted and kernel 
priority does not degrade.  User priorities on the other hand do degrade based 
upon system load and process CPU usage. 

non-kernel priority process priority is computed as follows:

     priority = P_USER + cpu_used/CPU_DIVISOR + nice_value*NICE_MULTIPLIER
where:
	P_USER is the constant 50
	CPU_DIVISOR is the constant 4
	NICE_MULTIPLIER is the constant 2


The P_USER term is added to prevennt a process from "aging" its way into
kernel priority.

Every 10ms the cpu component of the priority of a process is incremented, 
and whenever it is divisible by CPU_DIVISOR the process is moved to 
a lower queue.  

Once per second the cpu_component is recomputed to be:

	(new)cpu_usage = cpu_usage*load_decay_factor+nice_value
where:
	load_decay_factor = load_factor/(load_factor+1)
 	load_factor = DECAY_SCALE*load_average
	DECAY_SCALE is a constant whose value is 2
	load_average is the average number of waiting processes over the last 
		60 seconds

This will allow a process to be "forgiven" for time it has used in the past.
As the system becomes more loaded, the load_decay_factor approaches 1, making
the usage degrade more slowly.

Kernel priority is assigned when a process must sleep waiting for some event.
The idea is that since this process is going to be waiting for a while, it 
should be quickly restarted when the wait is over.  This will I/O bound
processes to make better progress.  When the process is awakened its priority
is raised until it is finished with the system call it had made, at which time
its priority is recomputed.  While sleeping, the cpu_usage term is 
aged as:

	(new)cpu_usage = cpu_usage*load_decay_factor^(seconds slept-1)

Once every 100 ms the scheduler recomputes prioritys of all processes to allow
multiple processes in the bottom queue to fight for time.  The scheduler can
also be invoked when an interrupt as been serviced.  

So, the answer to "what is the quantum" is approximately CPU_DIVISOR*10ms for
a system with "a normal load".  What a long winded answer to a simple 
question. Sigh. 


---
Bret Mckee

Hewlett Packard 
HP-UX Kernel Group
Phone:(303)229-6116	email: mckee%hpfcde at hplabs.hp.com 



More information about the Comp.unix.wizards mailing list