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}