From 0e48c476749b2483653c9a2ca308a3d162c8b16e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Gr=C3=A9goire?= Date: Wed, 19 Aug 2026 22:24:48 -0400 Subject: [PATCH] ke: move priority out of thread --- src/ex/work.zig | 4 +- src/kern/root.zig | 1 + src/kern/sched.zig | 22 +++++----- src/kern/thread.zig | 104 ++++++++++++++++++++++---------------------- src/proc/thread.zig | 2 +- 5 files changed, 67 insertions(+), 66 deletions(-) diff --git a/src/ex/work.zig b/src/ex/work.zig index 9af9d93..ab438f1 100644 --- a/src/ex/work.zig +++ b/src/ex/work.zig @@ -50,7 +50,7 @@ pub const WorkItem = struct { /// High priority work. High, - pub fn to_sched_prio(prio: Priority) ke.Thread.Priority { + pub fn to_sched_prio(prio: Priority) ke.Priority { return switch (prio) { .Low => .LowBatch, .Normal => .HighBatch, @@ -128,7 +128,7 @@ const Pool = struct { @ptrFromInt(ctx.value), ); - td.kern.nice = -ke.Thread.Priority.nice_max; + td.kern.nice = -ke.Priority.nice_max; if (cpu != null) { td.kern.last_cpu = cpu; diff --git a/src/kern/root.zig b/src/kern/root.zig index e2a775d..ab56ca2 100644 --- a/src/kern/root.zig +++ b/src/kern/root.zig @@ -21,6 +21,7 @@ pub const Queue = p.queue.Queue; pub const Mutex = p.mutex.Mutex; pub const ShootdownState = p.shootdown.ShootdownState; pub const Tunable = p.tunable.Tunable; +pub const Priority = p.thread.Priority; // === Exported Interfaces === pub const panic = p.panic.panic; diff --git a/src/kern/sched.zig b/src/kern/sched.zig index a6bfef9..28f714c 100644 --- a/src/kern/sched.zig +++ b/src/kern/sched.zig @@ -104,7 +104,7 @@ const pl = r.pl; const runqueues_n = 64; const interactivity_threshold = 30; const scaling_factor = 50; -const preempt_threshold = @intFromEnum(ke.Thread.Priority.LowRealtime); +const preempt_threshold = @intFromEnum(ke.Priority.LowRealtime); const balance_interval = @as(u64, config.sched_balance_interval); const steal_threshold = 1; const pct_window_target = 10 * std.time.us_per_s; @@ -536,7 +536,7 @@ fn recompute_priority(td: *ke.Thread) void { // Choose a priority based on score, the lower the score, // the higher the priority it will be. // This is a simple formula I came up with that is probably good enough. - @intCast(@intFromEnum(ke.Thread.Priority.LowInteractive) + + @intCast(@intFromEnum(ke.Priority.LowInteractive) + ((interactivity_threshold - score) / 2)) else blk: { // Thread is not interactive, compute priority from recent CPU usage. @@ -544,7 +544,7 @@ fn recompute_priority(td: *ke.Thread) void { // thread has spent running, we want to punish threads that got to run // a lot and reward threads that got starved. const len = @max(1, td.acct.stamp - td.acct.pct_window_start); - const cpu_range = ke.Thread.Priority.cpu_range; + const cpu_range = ke.Priority.cpu_range; const cpu_pri_off: u8 = @intCast(@min( cpu_range - 1, @@ -553,16 +553,16 @@ fn recompute_priority(td: *ke.Thread) void { // nice offset: negative nice increases priority value, // positive decreases it. - const nice_off: i16 = @as(i16, td.nice) + ke.Thread.Priority.nice_max; + const nice_off: i16 = @as(i16, td.nice) + ke.Priority.nice_max; - const raw: i16 = @as(i16, @intFromEnum(ke.Thread.Priority.HighBatch)) - + const raw: i16 = @as(i16, @intFromEnum(ke.Priority.HighBatch)) - @as(i16, cpu_pri_off) - nice_off; break :blk @intCast(std.math.clamp( raw, - @intFromEnum(ke.Thread.Priority.LowBatch), - @intFromEnum(ke.Thread.Priority.HighBatch), + @intFromEnum(ke.Priority.LowBatch), + @intFromEnum(ke.Priority.HighBatch), )); }; @@ -593,7 +593,7 @@ fn pick_realtime_thread(cpu: *PerCpu, minimum_prio: u8, migrate: bool) ?*ke.Thre if (runq.status == 0) return null; // Search higher priority queues first. - var i: usize = to_sched_prio(ke.Thread.Priority.max); + var i: usize = to_sched_prio(ke.Priority.max); qloop: while (i >= minprio and i > 0) : (i -= 1) { const bit = (@as(u64, 1) << @intCast(i)); @@ -754,7 +754,7 @@ fn insert_in_queue(cpu: *PerCpu, td: *ke.Thread, preempted: bool) void { // Insert in calendar queue. // The insertion index is determined by insidx and the the priority of the thread, // higher priority threads will be put closer to insidx, which ensures that they are ran more frequently. - var idx = (cpu.insidx + (@intFromEnum(ke.Thread.Priority.HighBatch) - + var idx = (cpu.insidx + (@intFromEnum(ke.Priority.HighBatch) - td.priority)) % runqueues_n; if (preempted) { @@ -861,7 +861,7 @@ fn select_thread(cur: ?*ke.Thread, cpu: *PerCpu, migrate: bool) ?*ke.Thread { // Return whether or not a thread with given priority and interactivity should // get preempted by `td`. fn should_prio_preempt(td: *ke.Thread, other_prio: u8, remote: bool) bool { - const class = ke.Thread.Priority.class_from_prio(other_prio); + const class = ke.Priority.class_from_prio(other_prio); if (td.priority <= other_prio) { // If our priority is lower or equal, ignore. @@ -874,7 +874,7 @@ fn should_prio_preempt(td: *ke.Thread, other_prio: u8, remote: bool) bool { } if (class == .Timeshare and td.is_interactive() and - other_prio < @intFromEnum(ke.Thread.Priority.LowInteractive) and remote) + other_prio < @intFromEnum(ke.Priority.LowInteractive) and remote) { // Interactive threads always preempt batch non-interactive ones // on remote CPUs. diff --git a/src/kern/thread.zig b/src/kern/thread.zig index 559f478..ff1f405 100644 --- a/src/kern/thread.zig +++ b/src/kern/thread.zig @@ -5,62 +5,62 @@ const rtl = @import("rtl"); const ke = r.ke; const ki = ke.private; -/// Structure representing a kernel thread. -pub const Thread = struct { - pub const Priority = enum(u8) { - const Self = @This(); +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, - _, + /// 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, - Timeshare, - Idle, - }; - - pub const max = 255; - pub const nice_max = 20; - - // 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 >= @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; - } + pub const Class = enum(u8) { + Realtime, + Timeshare, + Idle, }; + pub const max = 255; + pub const nice_max = 20; + + // 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 >= @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; + } +}; + +/// Structure representing a kernel thread. +pub const Thread = struct { /// Thread state. pub const State = enum(u8) { /// The thread is ready to run. diff --git a/src/proc/thread.zig b/src/proc/thread.zig index 288ce0b..f1dfc51 100644 --- a/src/proc/thread.zig +++ b/src/proc/thread.zig @@ -56,7 +56,7 @@ pub fn init() void { /// - `entry`: entry point. /// - `arg`: argument passed to `entry`. pub fn create_kernel( - prio: ke.Thread.Priority, + prio: ke.Priority, entry: *const fn (arg: ?*anyopaque) void, arg: ?*anyopaque, ) !*Thread {