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}