Microbenchmark Clojure功能

时间:2014-04-04 15:43:42

标签: clojure benchmarking

问题

assoc这样的小型Clojure功能有多快?我怀疑assoc在100ns到3us的范围内运行,这使得它很难计时。

使用time

user=> (def d {1 1, 2 2})
#'user/d
user=> (time (assoc d 3 3))
"Elapsed time: 0.04989 msecs"
{1 1, 2 2, 3 3}

显然有很多开销,所以我不相信这个基准。朋友们向我指出了Criterium,它处理了很多基准测试的痛苦(多次评估,预热JVM,GC见How to benchmark functions in Clojure?)。

使用Criterium

可悲的是,在如此小的基准上,甚至Criterium似乎都失败了

user=> (use 'criterium.core)
nil
user=> (def d {1 1 2 2})
#'user/d
user=> (bench (assoc d 3 3))
WARNING: JVM argument TieredStopAtLevel=1 is active, and may lead to unexpected results as JIT C2 compiler may not be active. See http://www.slideshare.net/CharlesNutter/javaone-2012-jvm-jit-for-dummies.
WARNING: Final GC required 1.694448681330372 % of runtime
Evaluation count : 218293620 in 60 samples of 3638227 calls.
             Execution time mean : -15.677491 ns
    Execution time std-deviation : 6.093770 ns
   Execution time lower quantile : -20.504699 ns ( 2.5%)
   Execution time upper quantile : 1.430632 ns (97.5%)
                   Overhead used : 123.496848 ns

万一你错过了,这个操作平均需要-15ns。我知道Clojure非常神奇,但负面的运行时似乎有点太好了。

重复问题

真的,assoc需要多长时间?如何在Clojure中对微操作进行基准测试?

3 个答案:

答案 0 :(得分:4)

答案 1 :(得分:4)

Criterium试图通过自己的测量来消除开销。这可能导致快速功能的负面结果。请参阅自述文件的Measurement Overhead Estimation部分。你的开销很可疑。您可以运行(estimatated-overhead!) [sic] 几次以获取更准确的开销数字。

答案 2 :(得分:4)

为什么不将它包装在循环中并重新规范化?

在我的硬件上,

(bench (dotimes [_ 1000] (assoc d 3 3)))

的平均执行时间约为

的1000倍
(bench (assoc d 3 3))

即,在第一种情况下约为100μs,在第二种情况下约为100ns。如果单个 - assoc对于Criterium来说是“噪音”,你可以尝试以相同的方式包装它并且非常接近“内在”值。 ((dotimes [_ 1000] 1)时钟为.59μs,因此环路本身施加的额外开销相对较小。)