From e51aeaa4987dbbaa9c5c95a8757130c5c31bb798 Mon Sep 17 00:00:00 2001 From: "shoney.arickathil" Date: Fri, 21 Aug 2026 16:13:10 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20time.ticks=20builtin=20=E2=80=94=20CLOC?= =?UTF-8?q?K=5FMONOTONIC=20us=20Int=20(id=2084)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - iteration 22's honest clock: monotone, never wall time; time.now stays ms. One types.ml row, sysio case, explicit dispatch arm (sys range gate stops at PROC_RUN) - corpus run/time-ticks (RED WO-E406 first); oop-e2e 104/0, full battery green; surface doc row (07-systems-stdlib absent, disclosed) Co-Authored-By: Claude Fable 5 --- compiler/src/types.ml | 1 + docs/plan/oop-vm/08-builtin-surface.md | 1 + docs/superpowers/plans/2026-08-21-db-bench.md | 20 ++++++------- runtime/src/builtin.c | 3 +- runtime/src/sysio.c | 8 ++++++ runtime/src/wob.h | 6 +++- tests/corpus/run/time-ticks/fixture.out | 2 ++ tests/corpus/run/time-ticks/fixture.wo | 28 +++++++++++++++++++ 8 files changed, 57 insertions(+), 12 deletions(-) create mode 100644 tests/corpus/run/time-ticks/fixture.out create mode 100644 tests/corpus/run/time-ticks/fixture.wo diff --git a/compiler/src/types.ml b/compiler/src/types.ml index 7ea7754..4e111e9 100644 --- a/compiler/src/types.ml +++ b/compiler/src/types.ml @@ -290,6 +290,7 @@ let stdlib_members : stdlib_member list = (* time *) m "time" "now" 0 0 (Some (TScalar "Int")) None; m "time" "sleep" 1 46 None None; + m "time" "ticks" 0 84 (Some (TScalar "Int")) None; m "time" "local" 1 47 (Some (TScalar time_record_name)) (Some time_record_name); m "time" "iso" 1 48 (Some (TScalar "Text")) None; (* env *) diff --git a/docs/plan/oop-vm/08-builtin-surface.md b/docs/plan/oop-vm/08-builtin-surface.md index 988e4e1..df6f0b6 100644 --- a/docs/plan/oop-vm/08-builtin-surface.md +++ b/docs/plan/oop-vm/08-builtin-surface.md @@ -273,6 +273,7 @@ unset `env.get` are nil. | `time.sleep(ms)` | — | | | `time.local(ms)` | `-> TimeParts` | `{ year, month, day, hour, minute, second, dow }`, dow 0 = Sunday | | `time.iso(ms)` | `-> Text` | UTC, second precision | +| `time.ticks()` | `-> Int` | CLOCK_MONOTONIC microseconds (id 84, iteration 22's bench clock) — monotone, never wall time; only differences mean anything | | `env.get(name)` | `-> ?Text` | unset is nil | | `env.stopping()` | `-> Bool` | SIGTERM/SIGINT latch, handlers installed on first use | | `net.listen(host, port)` | `-> Int` | IPv4, SO_REUSEADDR, backlog 64; returns an fd | diff --git a/docs/superpowers/plans/2026-08-21-db-bench.md b/docs/superpowers/plans/2026-08-21-db-bench.md index b950611..dd4c050 100644 --- a/docs/superpowers/plans/2026-08-21-db-bench.md +++ b/docs/superpowers/plans/2026-08-21-db-bench.md @@ -67,16 +67,16 @@ there). Story: the difference of two calls is a duration). Later tasks time every operation with it. -- [ ] Corpus fixture first: two `time.ticks()` calls around a spin loop; - assert the difference is non-negative and the second call is >= the - first (exact values are machine noise — the fixture asserts ordering - and that the builtin exists). Verify it FAILS today (unknown builtin). -- [ ] Wire the id (84), the sysio case (clock_gettime MONOTONIC, - seconds*1e6 + nsec/1e3, as Int), the compiler table rows, the two - contract-doc rows (name, arity 0, return Int µs, monotonic-not-wall - wording). -- [ ] Verify: fixture green under `just oop-e2e`; full battery green. - Commit. +- [x] Corpus fixture first (`run/time-ticks`): RED as WO-E406, then + green — asserts monotonicity + nonzero, values stay machine noise. +- [x] Wired: wob.h id 84 + WO_B_MAX bump; the sysio case; ONE compiler + table row (types.ml is the single stdlib table — the plan's guess of + sibling tables in owner/emit was wrong, no mirror needed); the sys + dispatch range needed an explicit `C == WO_B_TIME_TICKS` arm (the + range gate stops at PROC_RUN). DEVIATION: `07-systems-stdlib.md` + does not exist (a planned doc never written) — the row went into + `08-builtin-surface.md` alone. +- [x] Verified: oop-e2e 104/0 (was 103); full battery green. Commit. ## Task 2 — db-bench sample: tables, serial modes, per-op stats diff --git a/runtime/src/builtin.c b/runtime/src/builtin.c index 563fb40..cef1fa9 100644 --- a/runtime/src/builtin.c +++ b/runtime/src/builtin.c @@ -170,7 +170,8 @@ int wo_builtin(wo_vm *vm, uint64_t *R, uint32_t ins, const char **msg) { both ranges (WO_B_MAP_GET_OPT and anything added after it) stay here */ if (C == WO_B_JSON_ENCODE || C == WO_B_JSON_DECODE) return wo_builtin_json(vm, R, ins, msg); - if (C >= WO_B_SYS_FIRST && C <= WO_B_PROC_RUN) return wo_builtin_sys(vm, R, ins, msg); + if ((C >= WO_B_SYS_FIRST && C <= WO_B_PROC_RUN) || C == WO_B_TIME_TICKS) + return wo_builtin_sys(vm, R, ins, msg); if (C >= WO_B_DB_INSERT && C <= WO_B_DB_PROBE) { /* arc stage 3: the database is an actor on shard 0. A worker shard * has no engine by design — its statement marshals, parks, resumes diff --git a/runtime/src/sysio.c b/runtime/src/sysio.c index 67dda0d..add11db 100644 --- a/runtime/src/sysio.c +++ b/runtime/src/sysio.c @@ -284,6 +284,14 @@ int wo_builtin_sys(wo_vm *vm, uint64_t *R, uint32_t ins, const char **msg) { vm->cur->park_done = 1; return WO_SYS_PARKED; } + case WO_B_TIME_TICKS: { /* the bench clock: CLOCK_MONOTONIC µs as Int. + * Never wall time — only differences mean + * anything (iteration 22's honest percentiles) */ + struct timespec mts; + clock_gettime(CLOCK_MONOTONIC, &mts); + R[A] = (uint64_t)((int64_t)mts.tv_sec * 1000000 + mts.tv_nsec / 1000); + return 0; + } case WO_B_TIME_LOCAL: { /* Parts: 0 year, 1 month (1..12), 2 day, 3 hour, * 4 minute, 5 second, 6 dow (0 = Sunday) */ time_t secs = (time_t)((int64_t)R[B] / 1000); diff --git a/runtime/src/wob.h b/runtime/src/wob.h index ac5613a..2470486 100644 --- a/runtime/src/wob.h +++ b/runtime/src/wob.h @@ -430,9 +430,13 @@ enum { WO_B_TEXT_OF_BYTES = 83, /* (bytes) -> fresh Text, verbatim. The caller * asserts the bytes are text; no validation, * because Unicode is explicitly out of scope */ + WO_B_TIME_TICKS = 84, /* () -> Int, CLOCK_MONOTONIC microseconds — + * the bench clock (iteration 22). Monotone, + * never wall time: immune to NTP steps; only + * differences mean anything. */ }; -#define WO_B_MAX 83u +#define WO_B_MAX 84u /* ids at or above this one live in sysio.c, not builtin.c */ #define WO_B_SYS_FIRST WO_B_FS_EXISTS diff --git a/tests/corpus/run/time-ticks/fixture.out b/tests/corpus/run/time-ticks/fixture.out new file mode 100644 index 0000000..819829d --- /dev/null +++ b/tests/corpus/run/time-ticks/fixture.out @@ -0,0 +1,2 @@ +ticks: monotone +ticks: nonzero diff --git a/tests/corpus/run/time-ticks/fixture.wo b/tests/corpus/run/time-ticks/fixture.wo new file mode 100644 index 0000000..a3c2f94 --- /dev/null +++ b/tests/corpus/run/time-ticks/fixture.wo @@ -0,0 +1,28 @@ +use time + +-- time.ticks: CLOCK_MONOTONIC microseconds as Int. Values are machine +-- noise; the fixture asserts existence and ordering — a later reading +-- never precedes an earlier one, and a spin's elapsed is non-negative. +fn spin(rounds: Int) { + let i = 0; + while i < rounds { + i = i + 1; + } +} + +fn main() -> Int { + let t0 = time.ticks(); + spin(100000); + let t1 = time.ticks(); + if t1 >= t0 { + print("ticks: monotone"); + } else { + print("ticks: BACKWARDS ${t1 - t0}"); + } + if t0 > 0 { + print("ticks: nonzero"); + } else { + print("ticks: zero start"); + } + return 0; +}