7

在Criterion中对函数进行基准测试之前,如何强制评估函数的输入?我正在尝试对某些功能进行基准测试,但希望排除评估输入 thunk 的时间。有问题的代码使用未装箱的向量作为输入,对于Int向量不能进行 deepseq'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

同样,如果我只对“encode IntV”基准进行基准测试,我也会得到大约 150ns 的时间。

我从 Criterion 文档中知道,它试图避免惰性评估以进行更准确的基准测试。这是有道理的,在这里并不是真正的问题。我的问题是如何构建 shortv 和 intv 输入,以便在将它们传递给 bench 函数之前已经对其进行了评估。现在,我可以通过将 defaultMain 限制为一次只对一个函数进行基准测试来实现这一点(正如我刚刚在上面展示的那样),但这不是一个理想的解决方案。

编辑1

Criterion 基准测试还发生了其他事情,它似乎只发生在向量数组上,而不是列表上。如果我通过打印 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
4

1 回答 1

3

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

main = do
  evaluate shortv
  evaluate intv
  defaultMain [..]
于 2011-12-04T23:17:12.603 回答