diff --git a/lib/jit.sx b/lib/jit.sx new file mode 100644 index 00000000..7a0b8fca --- /dev/null +++ b/lib/jit.sx @@ -0,0 +1,89 @@ +;; lib/jit.sx — SX-level convenience wrappers over the JIT cache control +;; primitives (jit-stats, jit-set-threshold!, jit-set-budget!, jit-reset-cache!, +;; jit-reset-counters!). Host-specific implementations live in +;; hosts//lib/sx_*.ml; the API surface is portable across hosts. + +;; with-jit-threshold — temporarily set the JIT call-count threshold for +;; the duration of body, restoring the previous value on exit. Useful for +;; sections that want eager compilation (threshold=1) or want to skip JIT +;; entirely (threshold=999999) for diagnostic comparison. +(defmacro + with-jit-threshold + (n &rest body) + `(let + ((__old (get (jit-stats) "threshold"))) + (jit-set-threshold! ,n) + (let + ((__r (do ,@body))) + (jit-set-threshold! __old) + __r))) + +;; with-jit-budget — temporarily set the LRU cache budget. Setting to 0 +;; disables JIT entirely (everything falls through to the interpreter); +;; large values are effectively unbounded. +(defmacro + with-jit-budget + (n &rest body) + `(let + ((__old (get (jit-stats) "budget"))) + (jit-set-budget! ,n) + (let + ((__r (do ,@body))) + (jit-set-budget! __old) + __r))) + +;; with-fresh-jit — clear the cache before body, run body, clear again +;; after. Use between sessions / request batches / test suites where you +;; want deterministic timing free of carryover. +(defmacro + with-fresh-jit + (&rest body) + `(let + ((__r (do (jit-reset-cache!) ,@body))) + (jit-reset-cache!) + __r)) + +;; jit-report — human-readable summary of current JIT state. Returns a +;; string suitable for logging. +(define + jit-report + (fn + () + (let + ((s (jit-stats))) + (let + ((compiled (get s "compiled")) + (skipped (get s "below-threshold")) + (failed (get s "compile-failed")) + (evicted (get s "evicted")) + (cache-size (get s "cache-size")) + (budget (get s "budget")) + (threshold (get s "threshold"))) + (let + ((total (+ compiled skipped failed))) + (str + "jit: " cache-size "/" budget " cached " + "(thr=" threshold ") · " + compiled " compiled, " + skipped " below-thr, " + failed " failed, " + evicted " evicted " + "(" (if (> total 0) (* 100 (/ compiled total)) 0) "% compile rate)")))))) + +;; jit-disable! / jit-enable! — convenience helpers. Disabling sets budget +;; to 0 which causes the VM to skip JIT entirely on the next call. Enable +;; restores the budget to its previous value (or 5000 if no previous). +(define _jit-saved-budget (list 5000)) + +(define + jit-disable! + (fn + () + (set! _jit-saved-budget (list (get (jit-stats) "budget"))) + (jit-set-budget! 0))) + +(define + jit-enable! + (fn + () + (jit-set-budget! (first _jit-saved-budget))))