mirror of
https://github.com/rdmsr/zag.git
synced 2026-11-01 15:48:21 +00:00
ke: move priority out of thread
This commit is contained in:
+2
-2
@@ -50,7 +50,7 @@ pub const WorkItem = struct {
|
|||||||
/// High priority work.
|
/// High priority work.
|
||||||
High,
|
High,
|
||||||
|
|
||||||
pub fn to_sched_prio(prio: Priority) ke.Thread.Priority {
|
pub fn to_sched_prio(prio: Priority) ke.Priority {
|
||||||
return switch (prio) {
|
return switch (prio) {
|
||||||
.Low => .LowBatch,
|
.Low => .LowBatch,
|
||||||
.Normal => .HighBatch,
|
.Normal => .HighBatch,
|
||||||
@@ -128,7 +128,7 @@ const Pool = struct {
|
|||||||
@ptrFromInt(ctx.value),
|
@ptrFromInt(ctx.value),
|
||||||
);
|
);
|
||||||
|
|
||||||
td.kern.nice = -ke.Thread.Priority.nice_max;
|
td.kern.nice = -ke.Priority.nice_max;
|
||||||
|
|
||||||
if (cpu != null) {
|
if (cpu != null) {
|
||||||
td.kern.last_cpu = cpu;
|
td.kern.last_cpu = cpu;
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ pub const Queue = p.queue.Queue;
|
|||||||
pub const Mutex = p.mutex.Mutex;
|
pub const Mutex = p.mutex.Mutex;
|
||||||
pub const ShootdownState = p.shootdown.ShootdownState;
|
pub const ShootdownState = p.shootdown.ShootdownState;
|
||||||
pub const Tunable = p.tunable.Tunable;
|
pub const Tunable = p.tunable.Tunable;
|
||||||
|
pub const Priority = p.thread.Priority;
|
||||||
|
|
||||||
// === Exported Interfaces ===
|
// === Exported Interfaces ===
|
||||||
pub const panic = p.panic.panic;
|
pub const panic = p.panic.panic;
|
||||||
|
|||||||
+11
-11
@@ -104,7 +104,7 @@ const pl = r.pl;
|
|||||||
const runqueues_n = 64;
|
const runqueues_n = 64;
|
||||||
const interactivity_threshold = 30;
|
const interactivity_threshold = 30;
|
||||||
const scaling_factor = 50;
|
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 balance_interval = @as(u64, config.sched_balance_interval);
|
||||||
const steal_threshold = 1;
|
const steal_threshold = 1;
|
||||||
const pct_window_target = 10 * std.time.us_per_s;
|
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,
|
// Choose a priority based on score, the lower the score,
|
||||||
// the higher the priority it will be.
|
// the higher the priority it will be.
|
||||||
// This is a simple formula I came up with that is probably good enough.
|
// 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))
|
((interactivity_threshold - score) / 2))
|
||||||
else blk: {
|
else blk: {
|
||||||
// Thread is not interactive, compute priority from recent CPU usage.
|
// 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
|
// thread has spent running, we want to punish threads that got to run
|
||||||
// a lot and reward threads that got starved.
|
// a lot and reward threads that got starved.
|
||||||
const len = @max(1, td.acct.stamp - td.acct.pct_window_start);
|
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(
|
const cpu_pri_off: u8 = @intCast(@min(
|
||||||
cpu_range - 1,
|
cpu_range - 1,
|
||||||
@@ -553,16 +553,16 @@ fn recompute_priority(td: *ke.Thread) void {
|
|||||||
|
|
||||||
// nice offset: negative nice increases priority value,
|
// nice offset: negative nice increases priority value,
|
||||||
// positive decreases it.
|
// 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) -
|
@as(i16, cpu_pri_off) -
|
||||||
nice_off;
|
nice_off;
|
||||||
|
|
||||||
break :blk @intCast(std.math.clamp(
|
break :blk @intCast(std.math.clamp(
|
||||||
raw,
|
raw,
|
||||||
@intFromEnum(ke.Thread.Priority.LowBatch),
|
@intFromEnum(ke.Priority.LowBatch),
|
||||||
@intFromEnum(ke.Thread.Priority.HighBatch),
|
@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;
|
if (runq.status == 0) return null;
|
||||||
|
|
||||||
// Search higher priority queues first.
|
// 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) {
|
qloop: while (i >= minprio and i > 0) : (i -= 1) {
|
||||||
const bit = (@as(u64, 1) << @intCast(i));
|
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.
|
// Insert in calendar queue.
|
||||||
// The insertion index is determined by insidx and the the priority of the thread,
|
// 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.
|
// 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;
|
td.priority)) % runqueues_n;
|
||||||
|
|
||||||
if (preempted) {
|
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
|
// Return whether or not a thread with given priority and interactivity should
|
||||||
// get preempted by `td`.
|
// get preempted by `td`.
|
||||||
fn should_prio_preempt(td: *ke.Thread, other_prio: u8, remote: bool) bool {
|
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 (td.priority <= other_prio) {
|
||||||
// If our priority is lower or equal, ignore.
|
// 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
|
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
|
// Interactive threads always preempt batch non-interactive ones
|
||||||
// on remote CPUs.
|
// on remote CPUs.
|
||||||
|
|||||||
+52
-52
@@ -5,62 +5,62 @@ const rtl = @import("rtl");
|
|||||||
const ke = r.ke;
|
const ke = r.ke;
|
||||||
const ki = ke.private;
|
const ki = ke.private;
|
||||||
|
|
||||||
/// Structure representing a kernel thread.
|
pub const Priority = enum(u8) {
|
||||||
pub const Thread = struct {
|
const Self = @This();
|
||||||
pub const Priority = enum(u8) {
|
|
||||||
const Self = @This();
|
|
||||||
|
|
||||||
/// Reserved for the idle thread.
|
/// Reserved for the idle thread.
|
||||||
IdleThread = 0,
|
IdleThread = 0,
|
||||||
/// Background kernel work.
|
/// Background kernel work.
|
||||||
Idle = 1,
|
Idle = 1,
|
||||||
/// Low priority CPU-bound work
|
/// Low priority CPU-bound work
|
||||||
LowBatch = 2,
|
LowBatch = 2,
|
||||||
/// High priority CPU-bound work
|
/// High priority CPU-bound work
|
||||||
HighBatch = 137,
|
HighBatch = 137,
|
||||||
/// Low priority interactive work.
|
/// Low priority interactive work.
|
||||||
LowInteractive = 138,
|
LowInteractive = 138,
|
||||||
/// High priority interactive work.
|
/// High priority interactive work.
|
||||||
HighInteractive = 223,
|
HighInteractive = 223,
|
||||||
/// The default thread priority.
|
/// The default thread priority.
|
||||||
Default = 117,
|
Default = 117,
|
||||||
/// Low priority real-time work.
|
/// Low priority real-time work.
|
||||||
LowRealtime = 224,
|
LowRealtime = 224,
|
||||||
/// Mid priority real-time work.
|
/// Mid priority real-time work.
|
||||||
MidRealtime = 239,
|
MidRealtime = 239,
|
||||||
/// High priority real-time work.
|
/// High priority real-time work.
|
||||||
HighRealtime = 255,
|
HighRealtime = 255,
|
||||||
_,
|
_,
|
||||||
|
|
||||||
pub const Class = enum(u8) {
|
pub const Class = enum(u8) {
|
||||||
Realtime,
|
Realtime,
|
||||||
Timeshare,
|
Timeshare,
|
||||||
Idle,
|
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 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.
|
/// Thread state.
|
||||||
pub const State = enum(u8) {
|
pub const State = enum(u8) {
|
||||||
/// The thread is ready to run.
|
/// The thread is ready to run.
|
||||||
|
|||||||
+1
-1
@@ -56,7 +56,7 @@ pub fn init() void {
|
|||||||
/// - `entry`: entry point.
|
/// - `entry`: entry point.
|
||||||
/// - `arg`: argument passed to `entry`.
|
/// - `arg`: argument passed to `entry`.
|
||||||
pub fn create_kernel(
|
pub fn create_kernel(
|
||||||
prio: ke.Thread.Priority,
|
prio: ke.Priority,
|
||||||
entry: *const fn (arg: ?*anyopaque) void,
|
entry: *const fn (arg: ?*anyopaque) void,
|
||||||
arg: ?*anyopaque,
|
arg: ?*anyopaque,
|
||||||
) !*Thread {
|
) !*Thread {
|
||||||
|
|||||||
Reference in New Issue
Block a user