macrochrono / src / macrochrono.clj

(ns macrochrono
  "A collection of time measuring & benchmarking macros."
  {:author "Karsten Schmidt"})

(defmacro timed-action
  "Evaluates `body` in a do form and measures execution time.
  Returns result as 2-element vector: `[body-result time-in-msecs]`"
  [& body]
  `(let [t0# (System/nanoTime)]
     [(do ~@body) (* 1e-6 (- (System/nanoTime) t0#))]))

(defmacro bench
  "Evaluates `body` `num` times and returns map of execution time statistics:
  average, min, max and median times (all in ms). The result of the body
  expression is discarded. If `verbose?` is truthy, each intermediate timing
  is printed to `*out*`."
  ([num body] `(bench ~num ~body false))
  ([num body verbose?]
  `(loop [stats# [] i# ~num]
     (if (pos? i#)
       (let[[res# taken#] (timed-action ~body)]
         (if ~verbose? (prn (str "Elapsed time: " taken# " msecs")))
         (recur (conj stats# taken#) (dec i#)))
       {:avg (/ (reduce + stats#) ~num)
        :min (reduce min stats#)
        :max (reduce max stats#)
        :median (nth (sort stats#) (int (/ ~num 2)))}))))