Skip to content

Add a multi-level feedback queue (MLFQ) scheduler - #1117

Open
mutehimself wants to merge 1 commit into
theseus-os:theseus_mainfrom
mutehimself:mlfq-scheduler
Open

Add a multi-level feedback queue (MLFQ) scheduler#1117
mutehimself wants to merge 1 commit into
theseus-os:theseus_mainfrom
mutehimself:mlfq-scheduler

Conversation

@mutehimself

Copy link
Copy Markdown

Summary

Closes #1096. Adds kernel/scheduler_mlfq, a new scheduler policy alongside the existing round-robin/priority/epoch schedulers, selectable via THESEUS_CONFIG=mlfq_scheduler.

  • 8 priority levels; new tasks start at level 0 (highest priority), so short-lived/interactive tasks run promptly without ever being demoted.
  • Quanta grow linearly with level depth, so tasks that prove themselves CPU-bound are scheduled less often but for longer stretches.
  • Demotion is based on CPU time actually measured at dispatch, not on counting yields — a task can't dodge demotion by chunking CPU-bound work into pieces smaller than its quantum.
  • A task that's no longer runnable when charged (it blocked rather than exhausting its quantum) is never demoted — this is the mechanism that makes MLFQ favor interactive/I/O-bound tasks over CPU-bound ones, with no static classification required.
  • A periodic priority boost resets every task to level 0, bounding worst-case wait time and preventing starvation.
  • Implements PriorityScheduler, so scheduler::inherit_priority (used by sync_block to prevent unbounded priority inversion) keeps working correctly under this policy — without it, a lock holder could sit at a low MLFQ level while higher-priority waiters starved behind it.

Also updates ps to show the priority/level column under mlfq_scheduler, matching its existing behavior for the epoch/priority schedulers.

Benchmark (addresses #758)

scheduler_eval's only mode measured aggregate time for N identical tasks to yield, which can't distinguish a scheduler that favors interactive tasks from one that doesn't, since every task behaves the same way. Added a -m/--mixed mode that spawns a configurable mix of CPU-bound tasks (busy loop, never yields) and interactive tasks (short work bursts, yields between each), and reports each group's completion-latency distribution separately.

Results, one run each, 4 CPU-bound + 16 interactive tasks pinned to one CPU (run headlessly in QEMU via a first_application swap + isa-debug-exit, same mechanism qemu_test uses):

Scheduler CPU-bound avg latency Interactive avg latency Makespan
round-robin (default) 1382.3ms 772.0ms 1446.2ms
mlfq_scheduler 918.1ms 406.4ms 962.8ms

MLFQ roughly halves interactive-task latency relative to round-robin under identical CPU-bound contention, while also lowering CPU-bound latency and overall makespan (plausibly from fewer total context switches, since demoted tasks get longer quanta). Caveat: single run per scheduler under QEMU/TCG software emulation, so absolute numbers aren't representative of real hardware and the makespan difference in particular could partly reflect run-to-run emulation variance — the interactive-vs-CPU-bound ratio within each run is the more trustworthy comparison. Multiple trials and/or real hardware would firm this up further.

Test plan

  • cargo check against the x86_64-unknown-theseus target for scheduler_mlfq, spawn/ps (with --cfg mlfq_scheduler), and scheduler_eval.
  • Full make iso THESEUS_CONFIG=mlfq_scheduler build, booted in QEMU: clean SMP bring-up (4 CPUs), memory/ACPI/PCI/PS2/framebuffer init, shell loaded, no panics.
  • scheduler_eval -m run headlessly under both mlfq_scheduler and default round-robin for the comparison above.
  • Would appreciate maintainer input on whether BASE_QUANTUM/BOOST_INTERVAL (currently fixed constants) should be configurable, and on test coverage expectations for a new scheduler policy.

Closes theseus-os#1096. Adds kernel/scheduler_mlfq alongside the existing
round-robin/priority/epoch schedulers, selectable via
`THESEUS_CONFIG=mlfq_scheduler`.

- 8 priority levels; new tasks start at level 0 (highest priority), so
  short-lived/interactive tasks run promptly without ever being demoted.
- Quanta grow linearly with level depth, so tasks that prove themselves
  CPU-bound are scheduled less often but for longer stretches, amortizing
  context-switch overhead for exactly the workload that doesn't need low
  latency.
- Demotion is based on CPU time actually measured at dispatch (an Instant
  recorded when a task is picked, charged against it the next time `next`
  runs), not on counting yields, so a task can't dodge demotion by
  chunking CPU-bound work into pieces smaller than its quantum.
- A task that's no longer runnable when charged (it blocked rather than
  exhausting its quantum) is never demoted — this is the actual mechanism
  that makes MLFQ favor interactive/I/O-bound tasks over CPU-bound ones,
  with no static classification required.
- A periodic priority boost resets every task to level 0, bounding
  worst-case wait time and preventing starvation of long-demoted tasks.
- Implements `PriorityScheduler`, so `scheduler::inherit_priority` (used
  by `sync_block` to prevent unbounded priority inversion when a
  higher-priority task blocks on a lock held by a lower-priority one)
  keeps working correctly when this policy is selected.

Also updates `ps` to show the priority/level column under
`mlfq_scheduler`, matching its existing behavior for the epoch/priority
schedulers.

Benchmarked against round-robin via the `scheduler_eval -m` mode added
in the following commit: under a mix of 4 CPU-bound and 16 interactive
tasks pinned to one CPU, MLFQ roughly halves average interactive-task
completion latency (406ms vs. 772ms) relative to round-robin, while
also lowering CPU-bound latency and overall makespan.
mutehimself pushed a commit to mutehimself/MuteOS that referenced this pull request Aug 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Replace Round Robin scheduling with The Multi-Level Feedback Queue

1 participant