code wiki / (root) / nx_time_canonical.nx

nx_time_canonical.nx source

↩ module page · 79 lines · 2741 B

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