Repository navigation
Conversation
`Task::cmp` breaks priority ties by task ID (larger ID is greater) so that the preemption-pending heaps have a total order. The preemption decisions reused that ordering via `task > target_task`, so a task woken with the same priority as a running task preempted it whenever its ID was larger. This violates the FIFO order within a priority level, bypasses the RR time quantum, and costs a context switch with no scheduling benefit. It is most visible with small CPU sets, where "all CPUs in the set are busy" is the common case. Add `Task::preempts()`, which requires a strictly higher priority, and use it in every preemption decision: `invoke_preemption*()` of PrioritizedFIFO, PrioritizedRR, GEDF and ClusteredEDF, and the check in `do_preemption()` that re-queues a pending task when the running task on the target CPU has changed. `Task::cmp` is left as is for the heaps. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
ytakano
marked this pull request as ready for review
October 7, 2026 09:23
atsushi421
reviewed
Oct 7, 2026
atsushi421
left a comment
Contributor
There was a problem hiding this comment.
scripts/ci.sh cannot observe this change. The std feature enables no_preempt, which sets PREEMPTION_ENABLED to false and compiles out the IPI handler in preempt.rs. Please run test_prioritized_rr and test_prioritized_fifo on QEMU and note the result in the PR description. test_prioritized_rr expects every high-priority task to keep running, so it should show the quantum issue in the inline comment.
`PrioritizedRRScheduler::invoke_preemption_tick()` pushes the next runnable task to the preemption-pending heap without a priority check, and in RR that task normally has the same priority as the running one. With the strict comparison introduced in 82f9b6a, `do_preemption()` re-queued it every time, so the RR time quantum never switched tasks and the tick re-sent the IPI on every primary loop iteration. Let an equal-priority pending task preempt the running task when that task is PrioritizedRR. Every wake path requires a strictly higher priority, so this is the only case where equal priority preempts. Document the exception in `Task::preempts()` and the mdbook. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Collaborator
Author
Updated the description. |
atsushi421
approved these changes
Oct 16, 2026
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Task::cmpbreaks priority ties by task ID (larger ID is greater) so thatthe preemption-pending heaps have a total order. The preemption decisions
reused that ordering via
task > target_task, so a task woken with thesame priority as a running task preempted it whenever its ID was larger.
This violates the FIFO order within a priority level, bypasses the RR
time quantum, and costs a context switch with no scheduling benefit. It
is most visible with small CPU sets, where "all CPUs in the set are busy"
is the common case.
Add
Task::preempts(), which requires a strictly higher priority, anduse it in every preemption decision:
invoke_preemption*()ofPrioritizedFIFO, PrioritizedRR, GEDF and ClusteredEDF, and the check in
do_preemption()that re-queues a pending task when the running task onthe target CPU has changed.
Task::cmpis left as is for the heaps.The one exception is the PrioritizedRR time quantum:
invoke_preemption_tick()pushes the next runnable task to thepreemption-pending heap without a priority check, and
do_preemption()lets such an equal-priority pending task preempt a running PrioritizedRR
task so that the quantum keeps rotating tasks of the same priority. Every
wake path requires a strictly higher priority, so this is the only case
where equal priority preempts.
Related links
#726 will be resolved after this PR.
How was this PR tested?
scripts/ci.shpasses on my machine.make qemu-x86_64machine), built withmake x86_64 RELEASE=1 OPT="--release --features userland/<test>", serial consolecaptured to a file for 120 s.
test_prioritized_rr: 48 tasks (24 at priority 1, 24 at priority 0) on 15 workercores. In the last 30 s of the run, every one of the 24 priority-1 tasks logs
291-297 times (one line per 100 ms), and no priority-0 task logs. With the first
revision of this PR (before the RR exception in
do_preemption()), all 24priority-1 tasks still appear, but 13 of them (no=23..47) log 299-300 times, i.e.
they are never displaced, while no=1..21 get only 58-247: the time quantum did not
rotate tasks, and the only rotation came from the buffered-logger task preempting
the lowest-ID task.
test_prioritized_fifo: 15 low-priority (0) tasks start at t=4745-4758 ms and eachspawns a high-priority (31) task 100 ms later. All 15 high-priority tasks start at
4857-4859 ms and finish at 4957-4960 ms, and every low-priority task finishes after
that (4962-5064 ms). High priority preempts low priority immediately; no
equal-priority preemption is observed.
Notes for reviewers
do_preemption()now lets an equal-priority pending task throughwhen the running task is PrioritizedRR (time-quantum rotation). The
preempts()doccomment and the mdbook scheduler page describe the exception.
invoke_preemption_tick()keeps popping and re-queuing a lower-priority queue headon every primary loop iteration because
last_executed_timeis refreshed only ondispatch; each round also moves that task to the tail of its FIFO level. PrioritizedRR:
invoke_preemption_tick()pops and re-queues a lower-priority queue head on every primary loop iteration #729make x86_64withoutRELEASE=1) the serial log stops after 256buffered messages:
buffered_logger::run()counts withlet mut n: u8andn += 1overflows with overflow checks enabled. The QEMU results above thereforeuse
RELEASE=1. buffered_logger:u8counter overflow stops all log output after 256 messages in debug builds #728