77 lines
3.7 KiB
Plaintext
77 lines
3.7 KiB
Plaintext
;;;; The clock and the environment.
|
|
;;;;
|
|
;;;; Every line of output here is an invariant and not a reading, and that is
|
|
;;;; forced rather than chosen: this file is in the corpus @x86 builds twice
|
|
;;;; and diffs, and the acceptance table matches its stdout exactly, so a
|
|
;;;; timestamp or an elapsed count would fail a correct compiler on the second
|
|
;;;; run. What is left is what a clock actually has to promise — that it does
|
|
;;;; not go backwards, that a sleep does not return early, that the two faces
|
|
;;;; of one clock describe one instant — and those are the properties worth
|
|
;;;; pinning anyway. A test that asserted "this took under 3ms" would be a
|
|
;;;; test of the machine's load.
|
|
|
|
(defn main [] i32
|
|
;; Monotonic, twice. The whole contract in one line: it never goes
|
|
;; backwards. Equal is allowed and is not a bug — two reads inside one tick
|
|
;; of a coarse timer are the same nanosecond.
|
|
(let [t1 (monotonic-ns)
|
|
t2 (monotonic-ns)]
|
|
(println (>= t2 t1)))
|
|
|
|
;; And the origin is the first read rather than boot, so the first readings
|
|
;; a program takes are small. Bounded rather than pinned, and the bound is
|
|
;; deliberately loose: what separates this clock from a boot-relative one is
|
|
;; hours, so a minute proves it and a second only proved it on hardware. The
|
|
;; tighter bound was a reading after all — memcheck runs this program on a
|
|
;; synthetic CPU tens of times slower than the metal, the second genuinely
|
|
;; elapsed, and the line went false under a tool that has nothing to say
|
|
;; about clocks. A minute is past anything a simulator adds and still short
|
|
;; of the smallest thing the assertion is meant to catch.
|
|
(println (< (monotonic-ns) (* 60 ns-per-second)))
|
|
|
|
;; The f64 face is the i64 one divided, and what is checked is that the two
|
|
;; describe the same instant: a later reading in seconds is at or past an
|
|
;; earlier reading in nanoseconds converted the same way. A clock whose two
|
|
;; faces came from different sources fails this.
|
|
(let [a (/ (f64 (monotonic-ns)) 1000000000.0)
|
|
b (monotonic-seconds)]
|
|
(println (>= b a)))
|
|
|
|
;; The wall clock is a date, so the invariant is a date one: it is after
|
|
;; 2020 and before 2100. That pins the epoch and the unit at once — a clock
|
|
;; counting microseconds, or counting from boot, fails both halves.
|
|
(let [now (unix-seconds)]
|
|
(println (and (> now 1577836800.0) (< now 4102444800.0))))
|
|
|
|
;; Sleep is specified as *at least*, so at-least is what is asserted; the
|
|
;; upper bound belongs to the scheduler and not to this language. Two
|
|
;; milliseconds because the shortest sleep a default kernel actually
|
|
;; performs is a timer tick, and a shorter request would make this a test of
|
|
;; how that kernel was configured.
|
|
(let [before (monotonic-ns)]
|
|
(sleep-ns (* 2 ns-per-millisecond))
|
|
(println (>= (- (monotonic-ns) before) (* 2 ns-per-millisecond))))
|
|
|
|
;; Zero and negative return at once rather than being refused, which is what
|
|
;; a deadline already passed produces. That they return at all is the
|
|
;; assertion; nothing here is timed.
|
|
(sleep-ns 0)
|
|
(sleep-ns -1)
|
|
(sleep-seconds 0.0)
|
|
(println "slept")
|
|
|
|
;; ── The environment ──────────────────────────────────────────────
|
|
|
|
;; A variable nothing sets. None is the answer, and it is a different answer
|
|
;; from a variable set to nothing.
|
|
(match (getenv "FLAN_NO_SUCH_VARIABLE_AT_ALL")
|
|
(Some v) (println "unexpectedly set")
|
|
None (println "unset"))
|
|
|
|
;; PATH is set for every process that gets as far as running this, and the
|
|
;; only portable thing about its contents is that there are some.
|
|
(match (getenv "PATH")
|
|
(Some v) (println (> (len v) 0))
|
|
None (println "no PATH"))
|
|
0)
|