code wiki / (root) / time.nx

time.nx source

↩ module page · 76 lines · 2492 B

1// time.nx -- monotonic + wall clock, via Linux/NishiOS clock_gettime. 2// 3// Zero third-party runtime: only __syscall. Syscall 113 is 4// clock_gettime(clk_id, *timespec); returns 0 on success, -1 on error. 5// Linux RV64 numbers; NishiOS keeps the same set. 6// 7// TimeSpec layout matches Linux's `struct timespec`: two i64 fields, 8// seconds + nanoseconds. `var ts: TimeSpec` stack-allocates via the 9// compiler's alloca path; `&ts` hands the kernel a pointer to write 10// into. 11// 12// Callers generally want ns since some origin: 13// * monotonic_ns() -- ns since boot; cannot go backwards; immune to 14// wall-clock jumps (NTP, DST, manual set). Use for timing. 15// * wall_clock_ns() -- ns since Unix epoch; CAN jump. Use only for 16// human-readable timestamps and inter-machine correlation. 17 18// ---- syscall helpers ---- 19 20const CLOCK_REALTIME: i64 = 0 21const CLOCK_MONOTONIC: i64 = 1 22 23struct TimeSpec { 24 sec: i64, 25 nsec: i64, 26} 27 28func sys_clock_gettime(clk_id: i64, ts: *TimeSpec) -> i64 { 29 return __syscall(113, clk_id, ts as i64, 0, 0, 0, 0) 30} 31 32// ---- public API ---- 33 34// Nanoseconds since an unspecified monotonic origin (typically boot). 35// Non-decreasing, insensitive to wall-clock adjustments. 36func monotonic_ns() -> i64 { 37 var ts: TimeSpec 38 ts.sec = 0 39 ts.nsec = 0 40 sys_clock_gettime(CLOCK_MONOTONIC, &ts) 41 return ts.sec * 1000000000 + ts.nsec 42} 43 44// Nanoseconds since the Unix epoch (1970-01-01 00:00:00 UTC). 45// Can jump backward on clock adjustment; prefer monotonic_ns for 46// measuring durations. 47func wall_clock_ns() -> i64 { 48 var ts: TimeSpec 49 ts.sec = 0 50 ts.nsec = 0 51 sys_clock_gettime(CLOCK_REALTIME, &ts) 52 return ts.sec * 1000000000 + ts.nsec 53} 54 55// ===== self-test =================================================== 56// 57// Two cheap invariants: 58// * monotonic never decreases between two successive samples 59// * wall clock is positive and past 2020-01-01 (1577836800 seconds) 60// 61// Returns 0 on success; a small failure code indicates which check 62// failed (keeps the binary single-entry-point and diffable). 63 64func main() -> i64 { 65 let m1: i64 = monotonic_ns() 66 let m2: i64 = monotonic_ns() 67 if m2 < m1 { return 1 } 68 if m1 <= 0 { return 2 } 69 70 let w: i64 = wall_clock_ns() 71 // 2020-01-01 in ns. Any sane build machine passes. 72 let epoch_2020_ns: i64 = 1577836800000000000 73 if w < epoch_2020_ns { return 3 } 74 75 return 0 76}