- Published on
Introductory notes on the new Linux scheduler (EEVDF)
- Authors
- Name
- Vittorio Zaccaria
- @vzaccaria_en
I've recently updated the material of my Advanced Operating System course with an analysis of the new Linux EEVDF scheduler, which has supplanted the original CFS scheduler. I'll recap here my introductory notes, starting with a brief overview of the original scheduler (CFS).
The Completely Fair Scheduler (CFS)
CFS stands for “Completely Fair Scheduler,” and was the desktop process scheduler implemented by Ingo Molnar in Linux kernel version 2.6.23 up until version 6.14.
CFS assigned timeslices to each process dynamically based on total system load which is derived from the nice values of all runnable processes:
where
- is the load associated with a process, which is a function of the nice value . It has an exponential formula, i.e., (b=1.25). For numerical reasons is stored as weight . Most of the time however, the factor cancels out, and because it simplifies formulas, we are going to express formulas in terms of and not .
- was called schedule latency. Configurable, default 6ms. It was the targeted time for each process to get a chance to run.
- is called minimum granularity. Configurable, default 0.75ms. This ensured that that every low-priority process got a minimum amount of CPU time.
- is the process share of time.
To easily ensure fairness, CFS introduced a virtual runtime (vruntime)
variable as an absolute measure of the dynamic priority of each process whereby processes with lower are given priority because they lag behind. is influenced by the time that process has used and is inversely proportional to its load . The key reason for using is that it offers a straightforward way to directly compare processes with different priorities. Specifically, assuming that all processes start with the same , if each of them has been served for the assigned timeslice , all of them will end up again with the same because they have received the same amount of :
If a process has a lower it means that it lags behind and thus must be given priority. In fact, the process chosen for execution is the one with the minimum value of , i.e., . Such a variable is tracked as min_vruntime
in the runqueue and will play a role also in EEVDF.
CFS aimed for fairness but did not account for latency requirements well whereby some processes need quick access to the CPU but don't require much time1. CFS didn't offer a way to express these latency needs a part from specific latency-nice patches (which add a second nice value which controls when the CPU time will be available to that process) but a different and more streamlined solution has been cooking for sometime. Enter EEVDF.
Earliest Eligible Virtual Deadline First scheduler
EEVDF, based on a 1995 paper by Ion Stoica and Hussein Abdel-Wahab, has been introduced to address the above issues with latency. Like CFS, as of kernel 6.14.4, EEVDF divides CPU time fairly among processes by calculating the processes' "lag," or the difference between expected and actual service time; processes with positive lag are prioritized for scheduling. However, unlike CFS, EEVDF uses the concept of virtual deadlines to decide which process to run next allowing it to prioritize the latency-sensitive tasks.
EEVDF, like CFS, tracks the virtual runtime of each process, but introduces also the concept of global virtual time at time :
Intuitively, in an ideal system, if a unit of is passed then every process should have received an amount of time proportional to its load . If for some reason the virtual runtime of a process is less than then we say that the process lags behind and is owed CPU time.
In Linux, there is not an explicit variable that tracks . It is usually approximated with a weighted average of virtual runtimes of all running processes:
For numerical stability the kernel stores in two different variables called avg_vruntime
and avg_load
:
Here, min_vruntime
is used to reduce the magnitudes involved in computations (it is always equal to the minimum value of runtime you can find in the run queue at any given moment). Implicitly the value of could always be reconstructed from and as: .
As in CFS, tasks that are behind in virtual runtime must be given priority. In EEVDF, this means only eligible tasks (those with positive lag) can be scheduled, which ensures fairness.
To compute eligibility for process , the kernel measures the actual process lag, i.e., how much actual time do we owe to a process at time relative to the current virtual time:
A task is considered eligible when . The kernel tries hard to avoid loss in precision to compute if a task is eligible and in particular the actual formula used is is
Ensuring latency-sensitive operation
To prioritize among eligible tasks, EEVDF uses virtual deadlines to decide which process to run next. The virtual deadline represents the urgency with which a process should be scheduled, and the process with the earliest (smallest) virtual deadline is chosen to run first. The deadline is computed as
Unlike CFS, the timeslice of the process can be a default timeslice or a custom one set via the sched_setattr()
system call. The smaller the timeslice, the highest priority will be given to that eligible task.
Footnotes
Realtime scheduling classes could handle this, but they are somewhat used for privileged operations and can disrupt other processes if not handled well. Hence, the need for improvement in the normal scheduler. ↩