Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 

Repository files navigation

scx_interactive — an interactive-task-prioritizing Linux scheduler (sched_ext / eBPF)

A custom Linux CPU scheduler implemented as eBPF programs via the kernel's sched_ext framework (kernel >= 6.12; developed on 7.0.0, Ubuntu 26.04 ARM64). It classifies tasks as interactive vs. batch at runtime and prioritizes interactive tasks under CPU contention.

How it works

sched_ext is a scheduling class whose policy is supplied by BPF programs loaded from userspace. The kernel verifies the programs, JIT-compiles them, and migrates all tasks to the new policy; on exit, crash, or a 30s stall the kernel reverts everything to the default scheduler (EEVDF).

Task lifecycle through this scheduler:

  1. select_cpu — on wakeup, search for an idle CPU; if found, dispatch the task directly to that CPU's local queue (fast path, zero queueing).
  2. enqueue — otherwise insert into a shared queue ordered by virtual time (vtime). Two policy levers apply here:
    • Credit clamp: a waking task keeps up to 4 slices of vtime credit if interactive, 1 if batch — interactive tasks insert ahead.
    • Slice sizing: interactive tasks get 1/4-length slices (low latency for others), batch tasks full 20ms slices (cache warmth).
    • Preemption kick: interactive enqueue kicks the target CPU (SCX_KICK_PREEMPT) so priority takes effect immediately.
  3. dispatch — an idle CPU pulls the lowest-vtime task from the shared queue.
  4. stopping — the task is charged vtime = runtime x 100 / weight (weighted fairness: heavier tasks age slower, receiving more CPU).
  5. quiescent — voluntary sleeps are counted per task (BPF task storage);

    = 10 voluntary sleeps/sec over a 1s window => classified interactive.

Results

Workload: 8 stress-ng CPU hogs on 4 vCPUs (2:1 oversubscription). Probe: a task nanosleeping 1ms in a loop, 5000 samples/run; overshoot beyond 1ms = scheduling (wakeup) latency. One warm-up run discarded, 3 measured runs. UTM VM on Apple M3; host scheduler noise applies equally to both configs.

Scheduler p50 p99 (3 runs)
EEVDF (default) 59 us 302 / 426 / 599 us
scx_interactive v1 (no preemption) 26,764 us 47,985 us
scx_interactive v2 (preemption kick) 63–67 us 440 / 1,656 / 2,306 us

Findings:

  • v1 exposed the core lesson: vtime ordering without a preemption path is inert — a waking task waited out the incumbent's slice (median ~= half a 20ms slice). Adding a preemption kick on interactive enqueue improved median wakeup latency ~400x (26.7ms -> 63us).
  • A warm-up experiment isolated the remaining tail: with a cold probe, p99 ~= 38ms, dominated by the ~1s classification lag before the task earns interactive status; once classified, p99 drops to 0.4–2.3ms.
  • Steady state: parity with EEVDF at p50; EEVDF retains a ~4x better p99. Plausible contributors: single shared queue contention, kick targeting only the task's previous CPU, and 1s reclassification granularity.

Reproduce

# kernel >= 6.12 with CONFIG_SCHED_CLASS_EXT=y; clang >= 16, pahole >= 1.25
make all                                  # from repo root
sudo ./build/scheds/c/scx_interactive     # terminal 1
cat /sys/kernel/sched_ext/root/ops        # -> "interactive"
stress-ng --cpu 8 --timeout 200 &         # terminal 2
./latprobe                                # see scheds/c/ for source

Future work

Per-CPU or per-LLC queues to cut shared-queue contention; smarter kick target selection (lowest-priority running CPU); exponentially-decayed sleep rate to shrink classification lag; parameter sweep of slice sizes and thresholds.

Based on scx_simple (Meta Platforms, GPL-2.0).

About

Custom Linux CPU scheduler in eBPF (sched_ext): runtime interactive-task classification, vtime priority queue, preemption kick. Benchmarked vs EEVDF.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages