Skip to content

Commit

Permalink
Add documentation to perf ns, and add sleep arg to decrease GC's affe…
Browse files Browse the repository at this point in the history
…ct on timings.
  • Loading branch information
Alexander Taggart committed Oct 10, 2011
1 parent b916876 commit bb3a2aa
Showing 1 changed file with 69 additions and 23 deletions.
92 changes: 69 additions & 23 deletions src/test/clojure/clojure/data/codec/perf_base64.clj
Original file line number Diff line number Diff line change
Expand Up @@ -4,58 +4,85 @@
[clojure.string :as str])
(:use clojure.data.codec.base64))

(comment ;Example usage
(gen-data-file "data.in" 1 12 20) ; generate the data file to be used
(init-time-file "data.in" "time.out" 100) ; initialize timing file
(run-perf "data.in" "time.out" 100 false) ; add timings for (encode ...)
(run-perf "data.in" "time.out" 100 true) ; add timings for (encode! ...)
)

(set! *warn-on-reflection* true)

(defn rand-bytes [n]
(defn rand-bytes
"Returns a randomly populated byte-array of length n."
[n]
(->> #(byte (- (rand-int 256) 128))
repeatedly
(take n)
(byte-array)))

(defn gen-data-file [file from to times]
(defn gen-data-file
"Prints to file randomly generated byte vectors between lengths from and to,
inclusive, with times number of each length."
[file from to times]
(with-open [w (PrintWriter. (io/writer file))]
(binding [*out* w]
(doseq [n (range from (inc to))]
(doseq [_ (range 0 times)]
(println (into [] (rand-bytes n))))))))

(defn read-data-file [file]
(defn read-data-file
"Lazily reads a data file, returning a lazy sequence of byte-arrays."
[file]
(->> (line-seq (io/reader file))
(map read-string)
(map #(map byte %))
(map byte-array)))

(defmacro time-it [expr]
(defmacro time-it
"Like clojure.core/time, but returns the time in nanos instead of printing it."
[expr]
`(let [start# (System/nanoTime)
_# ~expr
stop# (System/nanoTime)]
(- stop# start#)))

(defn perf-clj [bas]
(defn perf-clj
"Returns a lazy sequence of encode timings for the given sequence of byte arrays."
[bas sleep]
(for [ba bas]
(do
(Thread/sleep 100)
(Thread/sleep sleep)
(time-it (encode ba)))))

(defn perf-clj-buf [bas]
(defn perf-clj-buf
"Returns a lazy sequence of encode! timings for the given sequence of byte arrays."
[bas sleep]
(let [out (memoize (fn [n] (byte-array (enc-length n))))]
(for [^bytes ba bas]
(let [len (alength ba)
output (out len)]
(do
(Thread/sleep 100)
(Thread/sleep sleep)
(time-it (encode! ba 0 len output)))))))

(defn perf-apache [bas]
(defn perf-apache
"Returns a lazy sequence of apache base64 encode timings for the given sequence of
byte arrays."
[bas sleep]
(for [ba bas]
(do
(Thread/sleep 100)
(Thread/sleep sleep)
(time-it (Base64/encodeBase64 ba)))))

(defn append-times [table times]
(defn append-times
"Lazily adds a column of timings to the given table."
[table times]
(map (fnil conj []) table times))

(defn write-time-file [table file]
(defn write-time-file
"Writes a table of timings to file."
[table file]
(with-open [w (PrintWriter. (io/writer file))]
(binding [*out* w]
(doseq [row table]
Expand All @@ -65,17 +92,20 @@
(print e))
(println)))))

(defn read-time-file [file]
(defn read-time-file
"Lazily reads a file containing a table of timings."
[file]
(->> (line-seq (io/reader file))
(map #(str/split % #"\t"))
(map vec)))

(defn init-perf-apache [bas]
(map #(vector (count %1) %2) bas (perf-apache bas)))

(defn third [[_ _ x]] x)

(defn latest-time-file [basis]
(defn latest-time-file
"Returns the name of the latest enumerated file with the given basis, or nil if it
doesn't exist."
[basis]
(let [dir (io/file ".")
nums (->> (.list dir )
(filter #(.startsWith ^String % basis))
Expand All @@ -86,22 +116,38 @@
(if (seq nums)
(format "%s.%03d" basis (apply max nums)))))

(defn next-time-file [file]
(defn next-time-file
"Returns the name of the next enumerated file after the given enumerated file name."
[file]
(if-let [[_ prefix suffix] (re-matches #"(.+\.)([0-9]{3})" file)]
(format "%s%03d" prefix (inc (Integer/parseInt suffix)))))

(defn init-time-file [data-file time-file]
(write-time-file (init-perf-apache (read-data-file data-file)) (str time-file ".000")))

(defn run-perf [data-file time-file use-buffer?]
(defn init-perf-apache
"Returns a lazy sequence of [count apache-timing] for each byte-array."
[bas sleep]
(map #(vector (count %1) %2) bas (perf-apache bas sleep)))

(defn init-time-file
"Using the given data file, creates a timing file using apache base64 encoding.
Sleep specifies the delay between iterations, thus reducing the chance of delays
from GC affecting the timing."
[data-file time-file sleep]
(write-time-file (init-perf-apache (read-data-file data-file) sleep) (str time-file ".000")))

(defn run-perf
"Using the given data file, adds a column of clojure base64 encode times to the
specified timing file. If use-buffer? is true, encode! will be used instead.
Sleep specifies the delay between iterations, thus reducing the chance of delays
from GC affecting the timing."
[data-file time-file sleep use-buffer?]
(let [prev-time-file (latest-time-file time-file)
next-time-file (next-time-file prev-time-file)]
(write-time-file
(append-times
(read-time-file prev-time-file)
(if use-buffer?
(perf-clj-buf (read-data-file data-file))
(perf-clj (read-data-file data-file))))
(perf-clj-buf (read-data-file data-file) sleep)
(perf-clj (read-data-file data-file) sleep)))
next-time-file)))


Expand Down

0 comments on commit bb3a2aa

Please sign in to comment.