Skip to content

Instantly share code, notes, and snippets.

@fsodomka
Last active December 19, 2015 03:29
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fsodomka/5890711 to your computer and use it in GitHub Desktop.
Save fsodomka/5890711 to your computer and use it in GitHub Desktop.
Helper functions for timing expressions and examples of use.
;; Copyright (c) Frantisek Sodomka
;; Distributed under the Eclipse Public License, the same as Clojure.
(defmacro timings [n & exprs]
`(if (= ~@exprs)
~(vec (for [expr exprs]
`(let [start# (System/nanoTime)
ret# (dotimes [~'_ ~n] ~expr)
end# (System/nanoTime)]
{:expr '~expr
:time (/ (- end# start#) 1e6)})))
(throw (Exception. "Results of expressions are not equal"))))
;; Reporting
(defn round [n x]
(let [p (Math/pow 10.0 n)]
(/ (Math/round (* x p)) p)))
(defn add-perc [tms]
(let [mx (apply max (map :time tms))]
(map #(assoc % :perc (round 2 (* 100 (/ (:time %) mx)))) tms)))
(defn add-ratio [tms]
(let [mn (apply min (map :time tms))]
(map #(assoc % :ratio (round 2 (/ (:time %) mn))) tms)))
(defn report [values]
(clojure.pprint/print-table
[:expr :time :ratio :perc]
(sort-by :time
(add-perc (add-ratio values)))))
;; Examples - arithmetic
(report (timings 1e7 (+ 1 2 3 4) (+ 1 (+ 2 (+ 3 4)))))
; | :expr | :time | :ratio | :perc |
; |---------------------+-----------+--------+-------|
; | (+ 1 2 3 4) | 55.985886 | 1.0 | 99.92 |
; | (+ 1 (+ 2 (+ 3 4))) | 56.030864 | 1.0 | 100.0 |
(report (let [x 1 y 42] (timings 1e7 (= x y) (== x y))))
; | :expr | :time | :ratio | :perc |
; |----------+-----------+--------+-------|
; | (== x y) | 54.037595 | 1.0 | 99.65 |
; | (= x y) | 54.227842 | 1.0 | 100.0 |
;; Examples - vectors
; Destructuring is better!
(report
(let [v [1 2 3]]
(timings 1e6
(let [[a b c] v]
(vector a b c))
(let [a (v 0) b (v 1) c (v 2)]
(vector a b c)))))
; | :expr | :time | :ratio | :perc |
; |------------------------------------------------+------------+--------+-------|
; | (let [[a b c] v] (vector a b c)) | 183.800175 | 1.0 | 86.26 |
; | (let [a (v 0) b (v 1) c (v 2)] (vector a b c)) | 213.070376 | 1.16 | 100.0 |
; Don't call 'first' on vectors
(report
(let [v (vec (range 1000))]
(timings 1e6
(v 0)
(nth v 0)
(first v))))
; | :expr | :time | :ratio | :perc |
; |-----------+------------+--------+-------|
; | (nth v 0) | 39.413389 | 1.0 | 24.19 |
; | (v 0) | 44.969123 | 1.14 | 27.6 |
; | (first v) | 162.919031 | 4.13 | 100.0 |
; LazySeq to PersistentVector conversion - into [] is twice as fast as vec
(report
(let [lst (range 1e5)]
(timings 10
(vec lst)
(apply vector lst)
(into [] lst)
(reduce conj [] lst))))
; | :expr | :time | :ratio | :perc |
; |----------------------+------------+--------+-------|
; | (into [] lst) | 73.725013 | 1.0 | 29.49 |
; | (vec lst) | 158.771017 | 2.15 | 63.5 |
; | (apply vector lst) | 159.247613 | 2.16 | 63.69 |
; | (reduce conj [] lst) | 250.029263 | 3.39 | 100.0 |
; PersistentList to PersistentVector conversion - vec is twice as fast as into []
(report
(let [lst (apply list (range 1e5))]
(timings 10
(vec lst)
(apply vector lst)
(into [] lst)
(reduce conj [] lst))))
; | :expr | :time | :ratio | :perc |
; |----------------------+------------+--------+-------|
; | (vec lst) | 84.877827 | 1.0 | 26.53 |
; | (apply vector lst) | 91.701319 | 1.08 | 28.66 |
; | (into [] lst) | 177.553292 | 2.09 | 55.49 |
; | (reduce conj [] lst) | 319.953514 | 3.77 | 100.0 |
;; ArrayList vs. PersistentVector - verifying results that vector is about 15% faster
;; https://news.ycombinator.com/item?id=5944438
(report
(let [v (vec (range 100000))
a (java.util.ArrayList. (range 100000))]
(timings 100
(reduce + v)
(reduce + a))))
; | :expr | :time | :ratio | :perc |
; |--------------+-------------+--------+--------|
; | (reduce + v) | 883.458372 | 1.00 | 87.45 |
; | (reduce + a) | 1010.263595 | 1.14 | 100.00 |
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment