ke: scheduler overhaul

This commit is contained in:
Loïc Grégoire
2026-08-19 18:04:12 -04:00
parent f78d10b62e
commit ee0c6aad67
13 changed files with 896 additions and 733 deletions
+1 -1
View File
@@ -125,7 +125,7 @@ pub fn init() void {
console_list.init();
const td = ps.thread.create_kernel(
ke.Thread.Priority.default,
.Default,
worker,
null,
) catch @panic("handle me");
+2 -2
View File
@@ -26,7 +26,7 @@ pub fn init() void {
if (rtl.cmdline.get_string(cline, "test")) |tst| {
// Run a test if specified.
if (r.tests.tests.get(tst)) |func| {
const t = ps.thread.create_kernel(ke.Thread.Priority.default, func, r.boot_info) catch @panic("oom");
const t = ps.thread.create_kernel(.Default, func, r.boot_info) catch @panic("oom");
ke.sched.enqueue(&t.kern);
} else {
std.log.info("invalid test: \"{s}\"", .{tst});
@@ -35,6 +35,6 @@ pub fn init() void {
}
if (r.boot_info.framebuffer != null) {
// fbconsole.init(boot_info);
// fbconsole.init(r.boot_info);
}
}
+7 -5
View File
@@ -50,11 +50,11 @@ pub const WorkItem = struct {
/// High priority work.
High,
pub fn to_sched_prio(prio: Priority) u8 {
pub fn to_sched_prio(prio: Priority) ke.Thread.Priority {
return switch (prio) {
.Low => ke.Thread.Priority.low_batch,
.Normal => ke.Thread.Priority.high_batch,
.High => ke.Thread.Priority.low_realtime,
.Low => .LowBatch,
.Normal => .HighBatch,
.High => .LowRealtime,
};
}
};
@@ -128,6 +128,8 @@ const Pool = struct {
@ptrFromInt(ctx.value),
);
td.kern.nice = -ke.Thread.Priority.nice_max;
if (cpu != null) {
td.kern.last_cpu = cpu;
td.kern.pinned = true;
@@ -312,7 +314,7 @@ pub fn init() !void {
try low.init(.Low, null);
var td = ps.thread.create_kernel(
ke.Thread.Priority.default,
.Default,
pool_manager,
null,
) catch @panic("Failed to create pool manager");
+1 -1
View File
@@ -17,7 +17,7 @@ export fn kmain(boot_info: *r.BootInfo) callconv(.c) void {
thread0.init(
boot_info.kernel_stack,
boot_info.kernel_stack_size,
ke.Thread.Priority.idle_low,
.IdleThread,
init,
null,
);
+825 -666
View File
File diff suppressed because it is too large Load Diff
+50 -48
View File
@@ -7,41 +7,55 @@ const ki = ke.private;
/// Structure representing a kernel thread.
pub const Thread = struct {
/// Thread priority classes.
/// Realtime: Highest priority, aggressively scheduled.
/// Batch: Normal priority.
/// Idle: For idle and background threads.
pub const Priority = struct {
pub const Priority = enum(u8) {
const Self = @This();
/// Reserved for the idle thread.
IdleThread = 0,
/// Background kernel work.
Idle = 1,
/// Low priority CPU-bound work
LowBatch = 2,
/// High priority CPU-bound work
HighBatch = 137,
/// Low priority interactive work.
LowInteractive = 138,
/// High priority interactive work.
HighInteractive = 223,
/// The default thread priority.
Default = 117,
/// Low priority real-time work.
LowRealtime = 224,
/// Mid priority real-time work.
MidRealtime = 239,
/// High priority real-time work.
HighRealtime = 255,
_,
pub const Class = enum(u8) {
Realtime,
Batch,
Timeshare,
Idle,
};
/// Idle thread has the lowest priority.
pub const idle_low = 0;
pub const idle = 1;
pub const max = 255;
pub const nice_max = 20;
/// Batch threads have priorities 2-23
pub const low_batch = 2;
pub const high_batch = 23;
pub const batch_range = high_batch - low_batch + 1;
/// Realtime threads have priorities 40-63
pub const low_realtime = 40;
pub const max = 63;
/// In the mid-range of batch threads
pub const default = 10;
/// Interactive threads have priorities 24-39
pub const low_interactive = 24;
pub const high_interactive = 39;
// The low and top 20 priorities from the batch range are reserved
// for nice.
pub const cpu_range = @intFromEnum(Self.HighBatch) - (nice_max * 2) - 1;
pub fn class_from_prio(prio: u8) Class {
if (prio >= low_realtime and prio <= max) return .Realtime;
if (prio >= low_batch and prio < low_realtime) return .Batch;
if (prio <= idle) return .Idle;
if (prio >= @intFromEnum(Self.LowRealtime) and
prio <= @intFromEnum(Self.HighRealtime))
return .Realtime;
if (prio >= @intFromEnum(Self.LowBatch) and
prio < @intFromEnum(Self.LowRealtime))
return .Timeshare;
if (prio <= @intFromEnum(Self.Idle))
return .Idle;
unreachable;
}
@@ -74,12 +88,6 @@ pub const Thread = struct {
base_priority: u8,
/// Priority inherited via priority donation.
inherited_prio: u8,
/// When the thread started sleeping.
sleep_start: u64,
/// Ticks spent voluntarily sleeping recently.
sleep_time: u64,
/// Ticks spent running recently.
run_time: u64,
/// Whether the thread is pinned to this CPU.
/// If it is pinned, then it can't be moved across another CPU.
pinned: bool,
@@ -116,6 +124,8 @@ pub const Thread = struct {
stack: r.VAddr,
/// PELT load average,
avg: ki.sched.Average,
/// Accounting statistics.
acct: ki.sched.Accounting,
/// Set whenever the thread is switching off its stack.
/// This is used to avoid taking thread next lock to wait for switch off
/// to complete.
@@ -132,7 +142,7 @@ pub const Thread = struct {
thread: *Thread,
stack: r.VAddr,
stack_size: usize,
prio: u8,
prio: Priority,
entry: *const fn (?*anyopaque) void,
arg: ?*anyopaque,
) void {
@@ -145,12 +155,9 @@ pub const Thread = struct {
),
.lock = .init(),
.nice = 0,
.priority = prio,
.base_priority = prio,
.priority = @intFromEnum(prio),
.base_priority = @intFromEnum(prio),
.inherited_prio = 0,
.sleep_start = 0,
.sleep_time = 0,
.run_time = 0,
.pinned = false,
.state = .init(.Ready),
.runq_link = .{},
@@ -170,14 +177,8 @@ pub const Thread = struct {
.queue_item = null,
.stack = stack,
.switching = .init(false),
.avg = .{
.last_update = .init(0),
// New threads are considered heavy until they prove themselves,
// this might allow for better balancing during bursts.
.load = ki.sched.pelt_load_avg_max,
.est = ki.sched.pelt_load_avg_max,
.period_contrib = 0,
},
.avg = .{},
.acct = .{},
.smr_sections = undefined,
};
@@ -201,7 +202,8 @@ pub const Thread = struct {
}
pub fn is_interactive(self: *Thread) bool {
return self.priority >= Priority.low_interactive and self.priority <= Priority.high_interactive;
return self.priority >= @intFromEnum(Priority.LowInteractive) and
self.priority <= @intFromEnum(Priority.HighInteractive);
}
};
+1 -1
View File
@@ -45,7 +45,7 @@ fn make_thread(
const td = mm.zone.gpa.create(ke.Thread) catch
@panic("Failed to allocate thread for AP");
td.init(stack, size, ke.Thread.Priority.idle_low, entrypoint, null);
td.init(stack, size, .IdleThread, entrypoint, null);
td.pinned = true;
return td;
+1 -1
View File
@@ -56,7 +56,7 @@ pub fn init() void {
/// - `entry`: entry point.
/// - `arg`: argument passed to `entry`.
pub fn create_kernel(
prio: u8,
prio: ke.Thread.Priority,
entry: *const fn (arg: ?*anyopaque) void,
arg: ?*anyopaque,
) !*Thread {
+2 -2
View File
@@ -154,12 +154,12 @@ fn particle(param: ?*anyopaque) void {
}
fn spawn_particle(arg: ?*anyopaque) void {
const t = ps.thread.create_kernel(ke.Thread.Priority.default, &particle, arg) catch @panic("OOM");
const t = ps.thread.create_kernel(.Default, &particle, arg) catch @panic("OOM");
ke.sched.enqueue(&t.kern);
}
fn spawn_explodeable() void {
const t = ps.thread.create_kernel(ke.Thread.Priority.default, &explodeable, null) catch @panic("OOM");
const t = ps.thread.create_kernel(.Default, &explodeable, null) catch @panic("OOM");
ke.sched.enqueue(&t.kern);
}
+1 -1
View File
@@ -169,7 +169,7 @@ pub fn start(_: ?*anyopaque) void {
is_parked[i] = .init(false);
const prio: u8 = @intCast(2 + (i * 5) % 29);
const t = ps.thread.create_kernel(prio, &worker, @ptrFromInt(i + 1)) catch @panic("oom");
const t = ps.thread.create_kernel(@enumFromInt(prio), &worker, @ptrFromInt(i + 1)) catch @panic("oom");
tds[i] = t;
ke.sched.enqueue(&t.kern);
}
+1 -1
View File
@@ -135,7 +135,7 @@ fn poller(_: ?*anyopaque) void {
}
fn spawn(entry: *const fn (?*anyopaque) void, id: usize) void {
const t = ps.thread.create_kernel(ke.Thread.Priority.default, entry, @ptrFromInt(id + 1)) catch @panic("oom");
const t = ps.thread.create_kernel(.Default, entry, @ptrFromInt(id + 1)) catch @panic("oom");
ke.sched.enqueue(&t.kern);
}
+1 -1
View File
@@ -279,7 +279,7 @@ fn quiesce_check() void {
}
fn spawn(prio: u8, entry: *const fn (?*anyopaque) void, id: usize) *ps.Thread {
const t = ps.thread.create_kernel(prio, entry, @ptrFromInt(id + 1)) catch @panic("oom");
const t = ps.thread.create_kernel(@enumFromInt(prio), entry, @ptrFromInt(id + 1)) catch @panic("oom");
ke.sched.enqueue(&t.kern);
return t;
}
+2 -2
View File
@@ -105,7 +105,7 @@ fn chain_high(_: ?*anyopaque) void {
}
fn spawn(prio: u8, entry: *const fn (?*anyopaque) void, arg: ?*anyopaque) *ps.Thread {
const t = ps.thread.create_kernel(prio, entry, arg) catch @panic("oom");
const t = ps.thread.create_kernel(@enumFromInt(prio), entry, arg) catch @panic("oom");
ke.sched.enqueue(&t.kern);
return t;
}
@@ -217,7 +217,7 @@ pub fn start(_: ?*anyopaque) void {
const prio: u8 = @intCast(2 + (i * 5) % 29);
stress_prio[i] = prio;
const t = ps.thread.create_kernel(prio, &stress, @ptrFromInt(i + 1)) catch @panic("oom");
const t = ps.thread.create_kernel(@enumFromInt(prio), &stress, @ptrFromInt(i + 1)) catch @panic("oom");
stress_tds[i] = t;
ke.sched.enqueue(&t.kern);
}