Skip to content

scheduler: add optional preemptive scheduling#2492

Open
stlankes wants to merge 1 commit into
hermit-os:mainfrom
stlankes:preempt
Open

scheduler: add optional preemptive scheduling#2492
stlankes wants to merge 1 commit into
hermit-os:mainfrom
stlankes:preempt

Conversation

@stlankes

Copy link
Copy Markdown
Contributor

The scheduler is tickless (a TSC-deadline one-shot timer), so a CPU-bound task that never blocks or yields keeps its core indefinitely. Add an optional preemptive feature that round-robins between ready tasks via a time slice.

A new Source::Preemption timer slot is armed for now + 10ms whenever the scheduler switches to a task while others are ready, and whenever custom_wakeup makes a task ready (so a freshly woken task preempts a non-yielding runner soon). When the slice expires, the timer handler's existing reschedule() switches to the next ready task. With no contention nothing is armed, so the system stays tickless.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmark Results

Details
Benchmark Current: 29c1147 Previous: f83a235 Performance Ratio
startup_benchmark Build Time 75.96 s 77.08 s 0.99
startup_benchmark File Size 0.73 MB 0.73 MB 1.00
Startup Time - 1 core 0.74 s (±0.02 s) 0.73 s (±0.02 s) 1.02
Startup Time - 2 cores 0.73 s (±0.03 s) 0.75 s (±0.02 s) 0.97
Startup Time - 4 cores 0.74 s (±0.02 s) 0.76 s (±0.02 s) 0.98
multithreaded_benchmark Build Time 76.11 s 80.66 s 0.94
multithreaded_benchmark File Size 0.86 MB 0.86 MB 1
Multithreaded Pi Efficiency - 2 Threads 91.53 % (±7.12 %) 89.44 % (±5.91 %) 1.02
Multithreaded Pi Efficiency - 4 Threads 44.56 % (±2.76 %) 44.06 % (±2.65 %) 1.01
Multithreaded Pi Efficiency - 8 Threads 25.44 % (±1.46 %) 25.56 % (±1.89 %) 1.00
micro_benchmarks Build Time 74.51 s 87.20 s 0.85
micro_benchmarks File Size 0.87 MB 0.87 MB 1.00
Scheduling time - 1 thread 65.26 ticks (±2.72 ticks) 67.04 ticks (±1.91 ticks) 0.97
Scheduling time - 2 threads 38.10 ticks (±5.76 ticks) 39.33 ticks (±3.42 ticks) 0.97
Micro - Time for syscall (getpid) 3.99 ticks (±0.66 ticks) 3.43 ticks (±0.24 ticks) 1.17
Memcpy speed - (built_in) block size 4096 84167.33 MByte/s (±58178.09 MByte/s) 84527.91 MByte/s (±58322.62 MByte/s) 1.00
Memcpy speed - (built_in) block size 1048576 30768.34 MByte/s (±24749.35 MByte/s) 30845.87 MByte/s (±25037.16 MByte/s) 1.00
Memcpy speed - (built_in) block size 16777216 29810.46 MByte/s (±24496.86 MByte/s) 27492.52 MByte/s (±22708.20 MByte/s) 1.08
Memset speed - (built_in) block size 4096 84555.10 MByte/s (±58440.10 MByte/s) 84666.80 MByte/s (±58421.97 MByte/s) 1.00
Memset speed - (built_in) block size 1048576 31524.29 MByte/s (±25199.03 MByte/s) 31593.14 MByte/s (±25470.12 MByte/s) 1.00
Memset speed - (built_in) block size 16777216 30594.55 MByte/s (±24954.62 MByte/s) 28269.66 MByte/s (±23193.64 MByte/s) 1.08
Memcpy speed - (rust) block size 4096 76959.39 MByte/s (±53568.72 MByte/s) 74722.10 MByte/s (±52209.99 MByte/s) 1.03
Memcpy speed - (rust) block size 1048576 30638.61 MByte/s (±24712.72 MByte/s) 30824.11 MByte/s (±25054.28 MByte/s) 0.99
Memcpy speed - (rust) block size 16777216 29788.25 MByte/s (±24472.89 MByte/s) 27597.67 MByte/s (±22766.03 MByte/s) 1.08
Memset speed - (rust) block size 4096 77376.97 MByte/s (±53862.94 MByte/s) 74865.22 MByte/s (±52302.23 MByte/s) 1.03
Memset speed - (rust) block size 1048576 31388.27 MByte/s (±25155.84 MByte/s) 31565.59 MByte/s (±25484.76 MByte/s) 0.99
Memset speed - (rust) block size 16777216 30570.69 MByte/s (±24928.35 MByte/s) 28374.92 MByte/s (±23250.83 MByte/s) 1.08
alloc_benchmarks Build Time 73.66 s 81.01 s 0.91
alloc_benchmarks File Size 0.81 MB 0.81 MB 1.00
Allocations - Allocation success 91.32 % 91.32 % 1
Allocations - Deallocation success 100.00 % 100.00 % 1
Allocations - Pre-fail Allocations 61.46 % 61.46 % 1
Allocations - Average Allocation time 6249.06 Ticks (±176.82 Ticks) 6133.98 Ticks (±129.62 Ticks) 1.02
Allocations - Average Allocation time (no fail) 6820.31 Ticks (±175.75 Ticks) 6784.80 Ticks (±184.79 Ticks) 1.01
Allocations - Average Deallocation time 1228.31 Ticks (±310.46 Ticks) 1292.85 Ticks (±344.36 Ticks) 0.95
mutex_benchmark Build Time 74.23 s 81.90 s 0.91
mutex_benchmark File Size 0.87 MB 0.87 MB 1.00
Mutex Stress Test Average Time per Iteration - 1 Threads 12.02 ns (±0.47 ns) 12.08 ns (±0.27 ns) 1.00
Mutex Stress Test Average Time per Iteration - 2 Threads 38.56 ns (±2.27 ns) 17.94 ns (±3.62 ns) 2.15

This comment was automatically generated by workflow using github-action-benchmark.

The scheduler is tickless (a TSC-deadline one-shot timer), so a CPU-bound
task that never blocks or yields keeps its core indefinitely. Add an
optional `preemptive` feature that round-robins between ready tasks via a
time slice.

A new `Source::Preemption` timer slot is armed for `now + 10ms` whenever the
scheduler switches to a task while others are ready, and whenever
`custom_wakeup` makes a task ready (so a freshly woken task preempts a
non-yielding runner soon). When the slice expires, the timer handler's
existing `reschedule()` switches to the next ready task. With no contention
nothing is armed, so the system stays tickless.
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.

2 participants