在Criterion中进行基准测试之前强制评估函数输入

时间:2011-12-04 22:44:53

标签: haskell lazy-evaluation criterion

Criterion中对函数进行基准测试之前,如何强制评估函数的输入?我试图对一些函数进行基准测试,但是想要排除评估输入thunk的时间。有问题的代码使用unboxed vectors作为输入,对于 Int 向量而言,这可能不是深层次的&#d。下面的示例代码段:

-- V is Data.Vector.Unboxed
shortv = V.fromList [1..10] :: V.Vector GHC.Int.Int16
intv = V.fromList [1..10] :: V.Vector GHC.Int.Int32

main :: IO ()
main = defaultMain [
          bench "encode ShortV" $ whnf encodeInt16V shortv
          ,bench "encode IntV" $ whnf encodeInt32V intv
       ]

标准基准包括在对上述功能进行基准测试时构建 shortv intv 输入的时间。标准测量值如下 - 每个函数测量约400ns,似乎也包括输入的构建时间:

benchmarking encode ShortV
mean: 379.6917 ns, lb 378.0229 ns, ub 382.4529 ns, ci 0.950
std dev: 10.79084 ns, lb 7.360444 ns, ub 15.89614 ns, ci 0.950

benchmarking encode IntV
mean: 392.2736 ns, lb 391.2816 ns, ub 393.4853 ns, ci 0.950
std dev: 5.565134 ns, lb 4.694539 ns, ub 6.689224 ns, ci 0.950 

现在,如果将基准代码的主要部分修改为以下(通过删除第二个工作台功能):

main = defaultMain [
          bench "encode ShortV" $ whnf encodeInt16V shortv
       ]
在对encodeInt16V函数进行基准测试之前,似乎评估了

shortv 输入。这对我来说确实是理想的输出,因为这个基准测量了函数执行的时间,不包括构建输入的时间。标准输出如下:

benchmarking encode ShortV
mean: 148.8488 ns, lb 148.4714 ns, ub 149.6279 ns, ci 0.950
std dev: 2.658834 ns, lb 1.621119 ns, ub 5.184792 ns, ci 0.950

同样,如果我只进行基准测试"编码IntV"基准测试,我也得到〜150ns的时间。

我从Criterion文档中了解到,它试图避免延迟评估以获得更准确的基准测试。这很有意义,而且这里不是一个问题。我的问题是如何构建shortv和intv输入,以便在传递到bench函数之前已经对它们进行了评估。现在,我可以通过限制defaultMain一次仅对一个函数进行基准测试来实现这一点(正如我上面所示),但这不是一个理想的解决方案。

EDIT1

此处还有其他一些Criterion基准测试,它似乎只发生在Vector数组上,而不是列表。如果我通过打印shortv和intv强制完全评估,基准测试仍然将时间测量为~400ns,而不是~150ns。代码更新如下:

main = do
  V.forM_ shortv $ \x -> do print x
  V.forM_ intv $ \x -> do print x
  defaultMain [
          bench "encode ShortV" $ whnf encodeInt16V shortv
          ,bench "encode IntV" $ whnf encodeInt32V intv
       ]

标准输出(也有158.4%的异常值似乎不正确):

estimating clock resolution...
mean is 5.121819 us (160001 iterations)
found 253488 outliers among 159999 samples (158.4%)
  126544 (79.1%) low severe
  126944 (79.3%) high severe
estimating cost of a clock call...
mean is 47.45021 ns (35 iterations)
found 5 outliers among 35 samples (14.3%)
  2 (5.7%) high mild
  3 (8.6%) high severe

benchmarking encode ShortV
mean: 382.1599 ns, lb 381.3501 ns, ub 383.0841 ns, ci 0.950
std dev: 4.409181 ns, lb 3.828800 ns, ub 5.216401 ns, ci 0.950

benchmarking encode IntV
mean: 394.0517 ns, lb 392.4718 ns, ub 396.7014 ns, ci 0.950
std dev: 10.20773 ns, lb 7.101707 ns, ub 17.53715 ns, ci 0.950

1 个答案:

答案 0 :(得分:3)

您可以在调用defaultMain之前使用evaluate来运行基准测试。不确定它是否是最干净的解决方案,但它看起来像这样:

main = do
  evaluate shortv
  evaluate intv
  defaultMain [..]