In this example, we'll be comparing a slow filter function with the built in function (BIF).
;; the slow filter function
(defn c-filter-recur
([pred items] (c-filter-recur pred (seq items) '()))
([pred items acc]
(cond
(empty? items) '()
(pred (first items)) (recur pred (rest items) (cons (first items) acc))
:else (recur pred (rest items) acc))))
At first we might want to use the BIF time
.
(def numbers (take 100 (repeatedly #(rand-int 42))))
(prn "recur")
(time (c-filter-recur even? numbers))
(prn "BIF")
(time (filter even? numbers))
example output:
"lazy"
"Elapsed time: 0.912789 msecs"
"BIF"
"Elapsed time: 0.021634 msecs"
If we run this more than once, we see that the time elapsed varies quite a bit. So, to solve this error margin, we can use benchmark
to take an average of multiple recorded times. Here is an example.
(def numbers (take 100 (repeatedly #(rand-int 100))))
(prn "recur")
(benchmark (c-filter-recur even? numbers))
(prn "BIF")
(benchmark (filter even? numbers))
example output:
"recur"
"Average elapsed time (1000 times): 0.0212918570 msecs"
"BIF"
"Average elapsed time (1000 times): 0.0002555670 msecs"
With benchmark
we can see that there is less variation. However, you will probably see quicker elapsed time because of the warm up procedure. Warmed up functions typically run faster.
Tip: See the documentation in benchmark.clj
for more options like customizing the number of recorded times, number of warm up times, and using the garbage collector.
If you are interested in using benchmark directly on a function, check out the code I wrote before combining these two. A macro
benchmark
for expressions andbenchmark*
for functions.