In my previous post on binary search I wanted to evaluate performance of two implementations. Clojure provides dotimes and time. Wouldn’t it be nice if we can string them together, parse output from time and calculate average execution time. Checking source of time and poking around I discovered with-out-str macro. It is quite simple. It just dynamically rebinds default output stream *out* to java.io.StringWriter. Having this the rest is piece of cake.

1 ( use ' [ clojure.contrib.str-utils :only ( re-split )])

2 ( defmacro time-avg

3 "Captures time output, parses it and calculates average.

4 Modeled after with-out-str. Example:

5 (time-avg

6 (dotimes [_ 5] (time (.run #(Thread/sleep (rand 100))))))"

7 [ & body ]

8 ` ( let [ s# ( java.io.StringWriter. )]

9 ( binding [ *out* s# ]

10 ~@ body )

11 ( let [ strng# ( str s# )

12 lns# ( re-split #"

" strng# )

13 flt-regex# #"\d+\.\d+"

14 lns-flts# ( filter #( re-seq flt-regex# % ) lns# )

15 flts# ( map

16 #( Float/parseFloat ( first ( re-seq flt-regex# % ) ))

17 lns-flts# )

18 sum# ( reduce + flts# )]

19 ( println strng# )

20 ( if ( seq flts# )

21 ( println "\"Average of" ( count flts# ) "run/s is"

22 ( / sum# ( count flts# ) ) "msecs\"" ) ) ) ) )

Starting on line 11 we parse output using regexes, look for doubles, sum them up and print calculated average. The only thing I stumbled on was using suffix # in macro variable names.