Clojureの関数がどれくらい時間がかかるかを計測する場合にはtime
を使うと手っ取り早い。
user=> (time (reduce + 0 (range 10000)))
"Elapsed time: 1.983 msecs"
49995000
timeは内部的にnanoTime
を使っているので精度も高いが使っていて困ったことがあった。
結果の計測値を標準出力に出して終わってしまうことだ。これは実装を見てみてわかった。
user=> (source time)
(defmacro time
"Evaluates expr and prints the time it took. Returns the value of
expr."
{:added "1.0"}
[expr]
`(let [start# (. System (nanoTime))
ret# ~expr]
(prn (str "Elapsed time: " (/ (double (- (. System (nanoTime)) start#)) 1000000.0) " msecs"))
ret#))
nil
この計測値を中で使いたい場合もある。メトリクスとしてとっておいて、何かの最適化とかデータとしてためておく場合など。そういった場合のマクロを書いてみた。
(defmacro with-time
[expr]
`(let [start# (. System (nanoTime))
ret# ~expr
elapsed# (/ (double (- (. System (nanoTime)) start#)) 1000000.0)]
[elapsed# ret#]))
基本はtimeの実装をほとんど流用しているけれど、こうすることで返り値の第一引数に計測値が入ってくる。
user=> (with-time (reduce + 0 (range 10000)))
[1.161 49995000]