diff --git a/benchmarks/benchmarks.clj b/benchmarks/benchmarks.clj index d83c1ad..75d309a 100644 --- a/benchmarks/benchmarks.clj +++ b/benchmarks/benchmarks.clj @@ -1,9 +1,12 @@ (ns taoensso.nippy.benchmarks {:author "Peter Taoussanis"} - (:use [taoensso.nippy :as nippy :only (freeze-to-bytes thaw-from-bytes)])) + (:use [taoensso.nippy :as nippy :only (freeze-to-bytes thaw-from-bytes)]) + (:require [taoensso.nippy.utils :as utils])) ;; Remove stuff from stress-data that breaks reader -(def bench-data (dissoc nippy/stress-data :queue :queue-empty :bytes)) +(def data (dissoc nippy/stress-data :queue :queue-empty :bytes)) + +(defmacro bench [& body] `(utils/bench 10000 (do ~@body) :warmup-laps 1000)) (defn reader-freeze [x] (binding [*print-dup* false] (pr-str x))) (defn reader-thaw [x] (binding [*read-eval* false] (read-string x))) @@ -11,30 +14,20 @@ (def roundtrip (comp thaw-from-bytes freeze-to-bytes)) (def reader-roundtrip (comp reader-thaw reader-freeze)) -(defmacro time-requests - "Warms up, then executes given number of requests and returns total execution - times in msecs." - [num-requests & body] - `(do (dotimes [_# (int (/ ~num-requests 4))] ~@body) ; Warm-up - (let [start-time# (System/nanoTime)] - (dotimes [_# ~num-requests] ~@body) - (Math/round (/ (- (System/nanoTime) start-time#) 1000000.0))))) - (comment ;;; Times (println "---\n" - (let [num 10000] - {:reader {:freeze (time-requests num (reader-freeze bench-data)) - :thaw (let [frozen (reader-freeze bench-data)] - (time-requests num (reader-thaw frozen))) - :round (time-requests num (reader-roundtrip bench-data))} + {:reader {:freeze (bench (reader-freeze bench-data)) + :thaw (let [frozen (reader-freeze bench-data)] + (bench (reader-thaw frozen))) + :round (bench (reader-roundtrip bench-data))} - :nippy {:freeze (time-requests num (freeze-to-bytes bench-data)) - :thaw (let [frozen (freeze-to-bytes bench-data)] - (time-requests num (thaw-from-bytes frozen))) - :round (time-requests num (roundtrip bench-data))}})) + :nippy {:freeze (bench (freeze-to-bytes bench-data)) + :thaw (let [frozen (freeze-to-bytes bench-data)] + (bench (thaw-from-bytes frozen))) + :round (bench (roundtrip bench-data))}}) ;; Clojure 1.3.0, Nippy 0.9.0 ;; {:reader {:freeze 23573, :thaw 31923, :round 53253}, diff --git a/src/taoensso/nippy/utils.clj b/src/taoensso/nippy/utils.clj index 6668f1c..fce02b6 100644 --- a/src/taoensso/nippy/utils.clj +++ b/src/taoensso/nippy/utils.clj @@ -10,4 +10,29 @@ `(case ~e ~@(map-indexed (fn [i# form#] (if (even? i#) (eval form#) form#)) clauses) - ~(when default default)))) \ No newline at end of file + ~(when default default)))) + +(defmacro time-ns + "Returns number of nanoseconds it takes to execute body." + [& body] + `(let [t0# (System/nanoTime)] + ~@body + (- (System/nanoTime) t0#))) + +(defmacro bench + "Repeatedly executes form and returns time taken to complete execution." + [num-laps form & {:keys [warmup-laps num-threads as-ms?] + :or {as-ms? true}}] + `(try (when ~warmup-laps (dotimes [_# ~warmup-laps] ~form)) + (let [nanosecs# + (if-not ~num-threads + (time-ns (dotimes [_# ~num-laps] ~form)) + (let [laps-per-thread# (int (/ ~num-laps ~num-threads))] + (time-ns + (->> (fn [] (future (dotimes [_# laps-per-thread#] ~form))) + (repeatedly ~num-threads) + doall + (map deref) + dorun))))] + (if ~as-ms? (Math/round (/ nanosecs# 1000000.0)) nanosecs#)) + (catch Exception e# (str "DNF: " (.getMessage e#))))) \ No newline at end of file