Linux sched_ext Explained: Extensible BPF Scheduling
Linux sched_ext is an optional kernel framework that lets a loaded BPF program define how eligible tasks are scheduled on CPUs. It is attracting attention because it makes scheduler experiments and workload-specific policies possible without maintaining a custom kernel patch. This explainer is for Linux developers, kernel engineers, and operators evaluating where the flexibility helps, and where the operational and policy risks remain.
What Is Linux sched_ext?
sched_ext is a Linux scheduler class whose scheduling behavior is defined by a set of BPF programs. The kernel still owns task state, CPU execution, and the mechanisms that move work onto a processor; the BPF scheduler supplies policy decisions such as where eligible tasks should wait and which should run next. The kernel’s sched_ext documentation describes its callbacks, dispatch queues, and lifecycle.
The feature is part of the Linux kernel, not a separate scheduler built into every distribution. A kernel must include sched_ext support, and a user-space loader must start a compatible BPF scheduler. The Linux kernel project publishes the kernel source and documentation; the sched_ext project provides example and production-oriented schedulers that use the interface.
Unlike a conventional kernel scheduler policy compiled into the kernel, a sched_ext policy can be loaded and unloaded while the system is running. It does not replace every scheduling class: real-time and deadline policies remain distinct. With the default sched_ext mode, ordinary fair-scheduled tasks can be handed to the BPF scheduler; a scheduler can also request partial switching so that only tasks explicitly using SCHED_EXT are managed by it.
Why sched_ext Exists
The built-in scheduler must serve many different workloads on different hardware. A desktop, a busy application server, and a machine running large batches may value different trade-offs among interactive latency, throughput, fairness, energy use, and cache locality. The built-in policies provide general-purpose behavior, but changing their core policy has traditionally required kernel development and often a patched kernel.
That makes testing scheduler ideas expensive. A researcher might want to compare task placement strategies; an operator might want to experiment with a policy tuned to a known workload. Kernel changes require review, rebuilding, deployment, and ongoing maintenance. A loadable BPF scheduler offers a way to prototype policy using the kernel’s supported extension interface.
Flexibility does not make a custom scheduler automatically faster or fairer. It can make poor decisions, mishandle assumptions about a workload, or perform differently after a kernel or hardware change. The value is that the policy can be tested and changed without rebuilding the kernel; it does not mean every system should replace its existing scheduler.
How sched_ext Works
The kernel calls BPF scheduler operations at scheduling events. A scheduler can, for example, make an initial CPU-selection hint when a task wakes, enqueue the task, and later provide work when a CPU needs something to run. The exact operations a scheduler implements depend on the design. CPU selection is a hint rather than a binding decision, and the task must still be eligible to execute on the selected CPU.
To connect BPF policy to the scheduler core, sched_ext uses dispatch queues, or DSQs. The kernel provides a global queue and a local queue for each CPU. A BPF scheduler can also create additional queues to represent its own policy. A CPU runs work from its local queue; tasks in other queues are moved to a CPU’s local queue when they are dispatched. This lets a scheduler make global placement decisions while keeping the final run queue close to the CPU that will execute the work.
The framework is designed to keep the kernel in control of safe execution. The BPF verifier checks properties such as program control flow and memory access before a program can run. sched_ext also monitors scheduler operation. If its BPF scheduler exits or the kernel detects an internal error, the kernel aborts that scheduler and returns affected tasks to the fair scheduler. This recovery path is an important safety property, not a guarantee that a custom policy will meet its performance goals or preserve every desired scheduling behavior.
| Concern | Built-in fair scheduling | sched_ext |
|---|---|---|
| Policy implementation | Kernel scheduler code | BPF scheduler loaded through the sched_ext interface |
| Changing policy | Usually requires an existing supported control or a kernel change | Load a different compatible scheduler without rebuilding the kernel |
| Task selection | General-purpose kernel policy | Scheduler-specific decisions using callbacks and dispatch queues |
| Failure behavior | Continues as part of the running kernel | On scheduler exit or detected error, tasks fall back to fair scheduling |
| Portability | Behavior follows the kernel version and configuration | Requires kernel support and a scheduler compatible with the target interface |
| Main trade-off | Less policy freedom, with mature general-purpose behavior | More control, plus responsibility to test behavior, performance, and compatibility |
The Linux API is separate from portable scheduling interfaces. The POSIX sched_setscheduler specification defines standard policy and priority interfaces; sched_ext is a Linux-specific extension for implementing scheduler policy.
Key Components and Concepts
Kernel configuration and scheduler class: sched_ext support is controlled by the kernel’s CONFIG_SCHED_CLASS_EXT option and relies on BPF support. It first appeared in mainline Linux 6.12, but the exact configuration and available features depend on the kernel build. A system can run Linux without exposing sched_ext.
BPF scheduler operations: A scheduler provides callbacks for events such as task selection, enqueueing, dispatch, and lifecycle changes. A scheduler may use only the operations needed for its policy. The kernel’s interface and available operations evolve, so a scheduler should be matched to the target kernel rather than assumed to work on every Linux release.
Dispatch queues: DSQs are the handoff point between policy code and per-CPU execution. The built-in global and per-CPU local queues support simple designs; additional queues allow a scheduler to organize tasks by workload, CPU group, or another policy-specific dimension.
Scheduling classes and opt-in: By default, sched_ext can manage ordinary SCHED_NORMAL, SCHED_BATCH, and SCHED_IDLE tasks while active. With partial switching, the BPF policy can be limited to tasks explicitly assigned the SCHED_EXT policy. These modes are materially different: operators must know which tasks the selected scheduler takes over.
Task weights and cgroups: Values such as task nice levels and cgroup CPU weights do not necessarily have the same meaning under every BPF scheduler. The kernel can report these settings to the scheduler, but the scheduler must implement the desired semantics and may choose not to. Check the scheduler’s documentation before relying on existing weight or resource-control behavior.
Fallback and observability: A scheduler’s status is exposed under /sys/kernel/sched_ext/; for example, state reports whether sched_ext is enabled, and root/ops identifies the active root scheduler. Fallback limits the impact of certain failures, but it does not replace monitoring, staged rollout, or a tested recovery plan.
Real-World Uses
- Scheduler research: Kernel developers and researchers can prototype placement and dispatch strategies without carrying a kernel patch for every iteration.
- Workload-specific experiments: A service with a well-understood mix of latency-sensitive and background tasks can test whether a different policy improves its measured goals. Results should be compared against the built-in scheduler under the same workload and load conditions.
- CPU topology experiments: A policy can group CPUs or consider workload placement in ways suited to a particular machine. Cache locality, migrations, power use, and hardware topology still need to be measured.
- Learning how scheduling behaves: The sched_ext project includes example schedulers that make the interface concrete. Examples are useful for understanding callbacks and queues, but they are not proof that the same policy is appropriate for a production host.
For broader CPU scheduling concepts and diagnostics, see OS resource management and CPU scheduling. If the question is what the kernel is doing during a performance problem, eBPF observability and kernel tracing covers tracing as a separate use of BPF.
Getting Started Safely
There is no standalone sched_ext package that works on every Linux distribution. Start with a test machine or virtual machine, a kernel that enables CONFIG_SCHED_CLASS_EXT and the needed BPF features, and a scheduler built for that kernel. The upstream sched_ext project documents its schedulers and installation/build requirements; distribution packages and prerequisites differ.
Check the running kernel and whether it exposes the sched_ext status interface:
uname -r
cat /sys/kernel/sched_ext/state
If the state file is missing, do not try to launch a scheduler: the running kernel may not include or expose sched_ext. Check the distribution’s kernel configuration and documentation. If the interface exists, find a scheduler installed for this system:
command -v scx_lavd
scx_lavd is one scheduler provided by the upstream project; it may not be packaged or installed on your distribution. Install a compatible build using the project’s instructions before running it. Launching a scheduler changes CPU scheduling policy for the host, so use a disposable test environment first:
sudo scx_lavd
In a second terminal, confirm the active state and scheduler name:
cat /sys/kernel/sched_ext/state
cat /sys/kernel/sched_ext/root/ops
Stop the scheduler with Ctrl+C in its foreground terminal. The kernel should unregister it and return tasks to the fair scheduler. If it exits unexpectedly, inspect the scheduler’s own output and kernel logs, then verify the state before trying again. Test representative workloads, latency, throughput, CPU migrations, and resource-control behavior before considering deployment. Do not infer that the fallback path makes an incompatible scheduler safe to deploy on an untested host.
Common Misconceptions
sched_ext is not simply a faster scheduler. It is an interface for supplying scheduling policy. Whether a policy improves throughput, latency, or energy use depends on the workload and the measurements.
BPF verification does not prove policy correctness. The verifier constrains what a program can do at runtime. It cannot ensure that the scheduler is fair, honors the operator’s intended priorities, or meets an application’s latency target.
The fallback mechanism is not a substitute for testing. The kernel can recover when a scheduler exits or an internal error is detected, but the workload may experience a disruption before or during fallback. Recovery does not validate the scheduler’s configuration or behavior.
Existing CPU weights may not retain their expected effect. Nice values and cgroup CPU weights depend on how the active BPF scheduler implements them. Confirm support in the selected scheduler instead of assuming that kernel controls map one-to-one to its policy.
Related Articles
- OS resource management and CPU scheduling
- eBPF observability and kernel tracing
- Linux cgroups: CPU, memory, and container limits
- Linux PSI and resource contention
Changelog and Last Updated
Last updated: October 12. Initial publication.

