What Is EEVDF in the Linux Kernel? – Best Linux Device Drivers Course

Linux Scheduling Classes and the EEVDF Scheduler – How Modern Kernels Pick the Next Thread

Part 3 of the CPU scheduler module in our free Linux kernel development course – modular scheduling classes, why CFS was retired, how EEVDF works, and sched_ext

Level
Intermediate
Series
CPU Scheduling – Lesson 3
Kernel
6.6+ (EEVDF), 6.12+ (sched_ext)

This lesson of our free Linux kernel development course goes inside the engine room. You already know that Linux offers several scheduling policies; now we look at how the kernel organizes them – through modular scheduling classes – and at the algorithm that runs the vast majority of threads on a modern machine: EEVDF, the Earliest Eligible Virtual Deadline First scheduler.

Important update for anyone learning from older books: the famous Completely Fair Scheduler (CFS), which powered Linux from kernel 2.6.23 (2007) to kernel 6.5, was replaced by EEVDF in kernel 6.6 (late 2023). And from kernel 6.12, Linux can even load custom schedulers written in BPF via sched_ext. This article – part of our free Linux device drivers course track – teaches the modern picture.

Topics Covered in This Lesson

Scheduling classes
EEVDF scheduler
CFS vs EEVDF
Virtual runtime
Virtual deadline
schedule() flow
sched_ext (BPF)

What You Will Learn

  • What a scheduling class is and the strict priority order of classes on Linux
  • How the core schedule() function walks the classes to pick the next thread
  • Why CFS was replaced and what problems EEVDF solves
  • The three ideas behind EEVDF: virtual runtime, lag/eligibility, and virtual deadline
  • How nice values translate into weights on modern kernels
  • What sched_ext is and why it matters for the future of Linux scheduling

Prerequisites

Lessons 1 and 2 of this series (the KSE and the scheduling policies). Familiarity with the idea of a red-black tree helps but is not required – we explain everything from first principles, as always in this free embedded systems course family.

Modular Scheduling Classes – One Kernel, Many Algorithms

Rather than hard-coding one giant algorithm, the Linux scheduler core is a thin dispatcher that delegates to scheduling classes. Each class implements a common set of operations – enqueue a thread, dequeue a thread, pick the next thread, handle the timer tick – and the core asks the classes, in strict priority order, “do you have anything to run?” The first class that answers wins.

Scheduling class hierarchy – checked top to bottom on every scheduling decision
Order Class Serves Notes
1 (highest) stop Kernel-internal per-CPU stopper thread Used for CPU hotplug, migration; not available to user space
2 deadline SCHED_DEADLINE threads Earliest-deadline-first with admission control
3 rt SCHED_FIFO and SCHED_RR threads Fixed priorities 1–99
4 fair SCHED_OTHER, SCHED_BATCH, SCHED_IDLE EEVDF on kernel 6.6+; previously CFS
5 ext Threads handed to a loaded BPF scheduler sched_ext, kernel 6.12+; optional
6 (lowest) idle The per-CPU idle thread (“swapper”) Runs only when nothing else is runnable

This ordering explains, mechanically, why any FIFO thread beats every SCHED_OTHER thread: the core never even asks the fair class while the rt class has a runnable thread.

The Flow of a Scheduling Decision

What happens when schedule() runs
1. Trigger
Thread blocks, timer tick expires slice, or a higher-priority thread wakes
↓
2. schedule() runs
Walks the classes: stop → deadline → rt → fair → ext → idle
↓
3. pick_next_task()
The first class with a runnable thread selects one
↓
4. Context switch
Register state and (if needed) address space swap; the chosen thread resumes on the CPU

From CFS to EEVDF – Why the Change?

CFS pursued one goal: long-term fairness. It tracked each thread’s virtual runtime (vruntime) – CPU time scaled by the thread’s weight – and always ran the thread with the smallest vruntime, stored at the leftmost node of a red-black tree. Fairness worked well, but latency did not have a first-class representation. Over the years CFS accumulated wakeup-preemption heuristics and tunables to approximate “run latency-sensitive threads soon”, and those heuristics were fragile and hard to reason about.

EEVDF keeps the fairness bookkeeping but adds latency as a native concept. Every runnable thread now has:

  • Virtual runtime (vruntime): weighted CPU time consumed, exactly as before – the fairness ledger.
  • Lag / eligibility: the difference between the CPU time a thread deserved and what it received. A thread is eligible only if it has not already taken more than its fair share (lag ≥ 0). Over-served threads must wait, which prevents any thread from banking unfair time.
  • Virtual deadline: computed as eligible time plus the thread’s slice scaled by weight. Threads that request shorter slices get earlier deadlines, and therefore run sooner.
EEVDF selection rule
Among all ELIGIBLE threads (lag ≥ 0), run the one with the EARLIEST virtual deadline

The beautiful consequence: latency-sensitive threads no longer rely on heuristics. A thread that runs briefly and often naturally keeps a small vruntime, stays eligible, and gets early deadlines – so it is chosen quickly after waking. A CPU hog gets long stretches but cannot exceed its fair share. Since kernel 6.12, a thread can even request a shorter slice via sched_setattr(), trading throughput for latency explicitly.

CFS vs EEVDF – what changed
Aspect CFS (kernel 2.6.23 – 6.5) EEVDF (kernel 6.6+)
Selection rule Smallest vruntime (leftmost tree node) Earliest virtual deadline among eligible threads
Latency handling Heuristics and tunables bolted on Built into the model via deadlines and slice requests
Fairness Long-term, via vruntime Long-term via vruntime plus bounded short-term unfairness via lag
Nice values Mapped to weights (~10% per step) Same weight table – behavior of nice is unchanged
User-visible policies OTHER / BATCH / IDLE Identical – no application changes needed

sched_ext – Bring Your Own Scheduler (Kernel 6.12+)

The newest development in this area is sched_ext: a scheduling class whose decisions are made by a BPF program loaded at runtime. Researchers and companies can now prototype application-specific schedulers (for games, for build farms, for telco workloads) without patching and rebooting the kernel. If the BPF scheduler ever misbehaves or exceeds its watchdog, the kernel automatically ejects it and falls back to EEVDF – a safe playground. For embedded engineers, this is worth watching: custom scheduling for a specific product workload is now a userspace-deployable artifact.

Hands-On: Observe the Modern Scheduler

# Confirm your kernel version (6.6+ means EEVDF)
uname -r

# Per-thread scheduler bookkeeping: vruntime, deadline and slice are visible
grep -E 'vruntime|deadline|slice' /proc/self/sched

# Watch context switches per second, system wide
vmstat 1 5     # 'cs' column = context switches/second

# Count voluntary vs involuntary switches for one thread
grep ctxt /proc/self/status

Voluntary switches happen when a thread blocks (waiting for I/O); involuntary (nonvoluntary) switches happen when the scheduler preempts it. The ratio instantly tells you whether a thread is I/O-bound or CPU-bound – a trick worth remembering for the profiling lesson coming later in this series.

Common Mistakes and Best Practices

  • Do not study only CFS in 2026. Interviewers increasingly ask about EEVDF. Learn vruntime and the eligibility/deadline additions.
  • Do not confuse the deadline class with EEVDF’s virtual deadlines. SCHED_DEADLINE is a real-time policy with hard guarantees; EEVDF’s virtual deadlines are an internal fairness/latency mechanism for normal threads.
  • Avoid cargo-cult tuning. Many CFS-era tunables were removed with EEVDF. Verify a knob exists on your kernel before scripting around it.
  • Remember the class order. Debugging “why does my thread never run?” almost always ends at a higher class monopolizing the CPU.

Interview Questions and Answers

Q1: What is a scheduling class in Linux?

A: A modular implementation of a scheduling algorithm exposing standard operations (enqueue, dequeue, pick next, tick). The core scheduler consults classes in fixed priority order – stop, deadline, rt, fair, (ext,) idle – and the first class with a runnable thread supplies the next task.

Q2: Which algorithm schedules normal threads on kernel 6.6 and later?

A: EEVDF – Earliest Eligible Virtual Deadline First. It replaced CFS as the fair-class algorithm while keeping the same user-visible policies and nice semantics.

Q3: What does “eligible” mean in EEVDF?

A: A thread is eligible when it has not yet consumed more CPU than its fair share – its lag is zero or positive. Only eligible threads are candidates; among them, the earliest virtual deadline wins.

Q4: How does a nice value influence scheduling internally?

A: It maps to a weight (roughly a 10% share change per nice step, a ~1.25× weight ratio between adjacent levels). The weight scales how fast vruntime advances: heavier threads accumulate vruntime slower and therefore receive proportionally more CPU.

Q5: What is sched_ext?

A: A scheduling class (kernel 6.12+) that delegates decisions to a BPF program loaded from user space, enabling custom schedulers without kernel rebuilds. The kernel falls back to the default fair scheduler if the BPF scheduler misbehaves.

FAQ

Did EEVDF change how I write applications?

No. Policies, nice values, and system calls are unchanged. EEVDF is an internal replacement; applications benefit from better latency without modification.

Is CFS still worth learning?

Understanding vruntime is still essential because EEVDF builds on it. But learn the full modern model – eligibility and virtual deadlines – since that is what ships in every current kernel.

Can I try a custom sched_ext scheduler safely?

Yes, on kernel 6.12+ with sched_ext enabled. A watchdog ejects a misbehaving BPF scheduler and control returns to EEVDF automatically.

Where do SCHED_FIFO threads fit in this picture?

They live in the rt class, which is consulted before the fair class – so any runnable FIFO/RR thread runs before any EEVDF-managed thread.

Is this lesson part of a free course?

Yes – the free Linux kernel development course at EmbeddedPathashala, which pairs with our free Linux device drivers course and free embedded systems course.

Key Takeaways

  • The scheduler core is a dispatcher over modular classes in strict order: stop → deadline → rt → fair → (ext) → idle.
  • Kernel 6.6 replaced CFS with EEVDF; kernel 6.12 added sched_ext for BPF-defined schedulers.
  • EEVDF = fairness via vruntime + bounded unfairness via lag/eligibility + latency via virtual deadlines.
  • Nice values still map to weights; user-visible behavior of policies is unchanged.
  • The class order mechanically explains all cross-policy priority rules.

Next in the Free Linux Kernel Development Course

Lesson 4 is fully practical: query and change the scheduling policy and priority of any thread – with chrt, system calls, and pthreads code.

← Previous Lecture
Next Lecture →

2 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *