all: type-safe time units

This commit is contained in:
Loïc Grégoire
2026-08-02 00:02:44 -04:00
parent 24372a2b4e
commit e36416304b
23 changed files with 137 additions and 61 deletions
+2 -2
View File
@@ -113,7 +113,7 @@ fn dispatch_queue(cpu: u32) void {
if (sched_cpu.start_timer) {
ke.timer.set(
&sched_cpu.resched_timer,
std.time.ns_per_ms * config.sched_timeslice,
.from(r.Milliseconds.init(config.sched_timeslice)),
.{ .dpc = &sched_cpu.resched_dpc },
);
}
@@ -123,7 +123,7 @@ fn dispatch_queue(cpu: u32) void {
ke.timer.cancel(&sched_cpu.resched_timer);
ke.timer.set(
&sched_cpu.resched_timer,
std.time.ns_per_ms * config.sched_timeslice,
.from(r.Milliseconds.init(config.sched_timeslice)),
.{ .dpc = &sched_cpu.resched_dpc },
);
}
+7 -1
View File
@@ -20,7 +20,13 @@ pub fn init(boot_info: *r.BootInfo) linksection(r.init) void {
ki.cpu.init_cpu(0);
ki.turnstile.init_turnstiles();
thread0.init(@intFromPtr(&stack), r.kib(16), ke.Thread.Priority.idle_low, ki.sched.idle, null);
thread0.init(
@intFromPtr(&stack),
r.kib(16),
ke.Thread.Priority.idle_low,
ki.sched.idle,
null,
);
thread0.priority = 0;
thread0.base_priority = 0;
thread0.pinned = true;
+7 -1
View File
@@ -89,6 +89,12 @@ pub fn log(
const ipl = out_lock.acquire_at(.High);
defer out_lock.release(ipl);
writer.interface.print("[{:>5}.{:06}] ", .{ res.info.timestamp / std.time.ns_per_s, (res.info.timestamp % std.time.ns_per_s) / std.time.ns_per_us }) catch return;
writer.interface.print(
"[{:>5}.{:06}] ",
.{
res.info.timestamp.value / std.time.ns_per_s,
(res.info.timestamp.value % std.time.ns_per_s) / std.time.ns_per_us,
},
) catch return;
_ = writer.interface.writeAll(res.buf[0..res.info.length]) catch return;
}
+1 -1
View File
@@ -92,7 +92,7 @@ const Desc = struct {
pub const Info = struct {
sequence: u64,
timestamp: u64,
timestamp: r.Nanoseconds,
length: u16,
};
+10 -10
View File
@@ -215,7 +215,7 @@ pub const Average = struct {
// Amount of the period that has been accounted for
period_contrib: usize,
/// Timestamp (us) up to which history has been accounted.
last_update: u64,
last_update: r.Microseconds,
};
pub const percpu = ke.CpuLocal(PerCpu, undefined);
@@ -242,8 +242,8 @@ fn pelt_do_decay(val: u64, n: u64) u64 {
}
fn pelt_update(avg: *Average, runnable: bool) void {
const now = ke.time.read_time() / std.time.ns_per_us;
const new_delta = now - avg.last_update;
const now = ke.time.read_time().to(r.Microseconds);
const new_delta = now.value - avg.last_update.value;
if (new_delta == 0) return;
@@ -318,8 +318,8 @@ fn pelt_update_td(td: *ke.Thread, cpu: ?*PerCpu, runnable: bool) void {
fn attach_load_avg(cpu: *PerCpu, td: *ke.Thread) void {
if (!tracks_load_avg(td)) return;
if (td.avg.last_update == 0) {
td.avg.last_update = ke.time.read_time() / std.time.ns_per_us;
if (td.avg.last_update.value == 0) {
td.avg.last_update = ke.time.read_time().to(r.Microseconds);
} else {
pelt_update_td(td, null, false);
}
@@ -470,7 +470,7 @@ pub fn block() void {
/// Block the currently running thread with its lock held.
pub fn block_locked(curtd: *ke.Thread) void {
curtd.state.store(.Blocked, .monotonic);
curtd.sleep_start = ke.time.read_time();
curtd.sleep_start = ke.time.read_time().value;
curtd.runq = null;
detach_load_avg(percpu.local(), curtd);
@@ -537,7 +537,7 @@ pub fn unblock_locked(td: *ke.Thread) void {
std.debug.assert(td.lock.is_locked());
std.debug.assert(td.state.load(.monotonic) == .Blocked);
const delta = (ke.time.read_time() - td.sleep_start) / std.time.ns_per_ms;
const delta = (ke.time.read_time().value - td.sleep_start) / std.time.ns_per_ms;
td.sleep_time += delta;
@@ -685,7 +685,7 @@ pub fn late_init() linksection(r.init) void {
balance_timer.init();
ke.timer.set(
&balance_timer,
balance_interval * std.time.ns_per_ms,
.from(r.Milliseconds.init(balance_interval)),
.{ .dpc = &balance_dpc },
);
}
@@ -1136,7 +1136,7 @@ fn pick_cpu(td: *ke.Thread) u32 {
var ran_recently = true;
if (td.sleep_start != 0) {
const delta = ke.time.read_time() - td.sleep_start;
const delta = ke.time.read_time().value - td.sleep_start;
// If we haven't been on this CPU in the last second, don't bother.
if (delta > std.time.ns_per_s) {
@@ -1455,5 +1455,5 @@ fn balance(_: *ke.Dpc, _: ?*anyopaque) void {
const offset = lcg.next() % balance_interval;
const ms = (balance_interval) + offset;
ke.timer.set(&balance_timer, ms * std.time.ns_per_ms, .{ .dpc = &balance_dpc });
ke.timer.set(&balance_timer, .from(r.Milliseconds.init(ms)), .{ .dpc = &balance_dpc });
}
+1 -1
View File
@@ -159,7 +159,7 @@ pub const Thread = struct {
.stack = stack,
.switching = .init(false),
.avg = .{
.last_update = 0,
.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,
+5 -5
View File
@@ -89,12 +89,12 @@ pub fn register_source(tc: *TimeCounter) void {
/// Return the time elapsed since boot in nanoseconds.
pub fn read_time() r.Nanoseconds {
const tc = best_tc orelse return 0;
const tc = best_tc orelse return .init(0);
const s = state.load();
const curr_count = tc.read_count() & tc.mask;
const elapsed = (curr_count - s.initial_count) & tc.mask;
return s.offset + ticks_to_ns(tc, elapsed);
return .init(s.offset + ticks_to_ns(tc, elapsed));
}
/// Return the best TimeCounter.
@@ -109,14 +109,14 @@ pub fn sleep(ns: r.Nanoseconds) void {
while (true) {
var cur = read_time();
if (cur < start) continue;
if (cur.value < start.value) continue;
if (cur - start >= ns) {
if (cur.value - start.value >= ns.value) {
cur = read_time();
// Check again as we may have overflowed and read a bogus value..
// This is kinda hacky but oh well.
if (cur - start >= ns) {
if (cur.value - start.value >= ns.value) {
break;
}
}
+7 -7
View File
@@ -42,7 +42,7 @@ pub const Timer = struct {
self.* = .{
.hdr = undefined,
.state = .init(.Stopped),
.deadline = 0,
.deadline = .init(0),
.dpc = null,
.node = .{},
.cpu = null,
@@ -79,7 +79,7 @@ pub fn set(timer: *Timer, time: r.Nanoseconds, opts: Options) void {
defer cpu.lock.release_no_ipl();
// Initialize the timer.
timer.deadline = ke.time.read_time() + time;
timer.deadline = .init(ke.time.read_time().value + time.value);
timer.cpu = cpu;
timer.dpc = opts.dpc;
@@ -130,7 +130,7 @@ pub fn cmp_timer(a: *rtl.pairing_heap.Node, b_: *rtl.pairing_heap.Node) std.math
const timer_a: *Timer = @fieldParentPtr("node", a);
const timer_b: *Timer = @fieldParentPtr("node", b_);
return std.math.order(timer_a.deadline, timer_b.deadline);
return std.math.order(timer_a.deadline.value, timer_b.deadline.value);
}
/// Called by the platform on a clock interrupt.
@@ -161,18 +161,18 @@ fn handle_expiry(_: *ke.Dpc, _: ?*anyopaque) void {
// If the timer expires more than 1ms in the future, consider it not yet due.
// Sub-millisecond differences are close enough to expire immediately.
if (timer.deadline > curtime and timer.deadline - curtime > std.time.ns_per_ms) {
if (timer.deadline.value > curtime.value and timer.deadline.value - curtime.value > std.time.ns_per_ms) {
const next = timer;
cpu.lock.release_no_ipl();
// Re-check in case the timer expired while we were here.
const now = ke.time.read_time();
if (next.deadline <= now or next.deadline - now <= std.time.ns_per_ms) {
if (next.deadline.value <= now.value or next.deadline.value - now.value <= std.time.ns_per_ms) {
continue; // expired in the meantime, loop again
}
std.debug.assert(next.deadline > now);
pl.arm_timer(next.deadline - now);
std.debug.assert(next.deadline.value > now.value);
pl.arm_timer(.init(next.deadline.value - now.value));
return;
}
+1 -1
View File
@@ -166,7 +166,7 @@ pub fn wait_any(objects: []*DispatchHeader, reason: []const u8, opts: Options) !
}
// Wait was already satisfied, back out.
if (satisfier != null or (has_timeout and opts.timeout.? == 0)) {
if (satisfier != null or (has_timeout and opts.timeout.?.value == 0)) {
if (satisfier != null) {
std.debug.assert(curtd.wait_status.load(.acquire) == .Satisfied);
}