如何为Criterion基准创建数据?

Jan*_*rek 10 haskell haskell-criterion

我使用标准来对我的Haskell代码进行基准测试.我正在做一些繁重的计算,我需要随机数据.我写了这样的主要基准文件:

main :: IO ()
main = newStdGen >>= defaultMain . benchmarks

benchmarks :: RandomGen g => g -> [Benchmark]
benchmarks gen =
   [
     bgroup "Group"
     [
       bench "MyFun" $ nf benchFun (dataFun gen)
     ]
   ]
Run Code Online (Sandbox Code Playgroud)

我在不同的模块中为它们保留基准和数据生成器:

benchFun :: ([Double], [Double]) -> [Double]
benchFun (ls, sig) = fun ls sig

dataFun :: RandomGen g => g -> ([Double], [Double])
dataFun gen = (take 5 $ randoms gen, take 1024 $ randoms gen)
Run Code Online (Sandbox Code Playgroud)

这有效,但我有两个问题.首先,生成基准中包含的随机数据所需的时间是多少?我发现了一个涉及该主题的问题,但说实话,我无法将其应用于我的代码.为了检查是否发生这种情况,我在IO monad中编写了一个替代版本的数据生成器.我将基准列表与main(称为生成器)放在一起,用< - 提取结果,然后将其传递给基准函数.我发现性能没有差别.

我的第二个问题涉及生成随机数据.现在,生成器一旦创建就不会更新,这会导致在一次运行中生成相同的数据.这不是一个主要问题,但尽管如此,它仍然很好.有没有一种巧妙的方法在每个数据*函数中生成不同的随机数据?"整洁"意味着"没有使数据功能在IO中获取StdGen"?

编辑:如下面评论中所述,我并不关心数据随机性.对我来说重要的是,生成数据所需的时间不包括在基准测试中.

jbe*_*man 7

这有效,但我有两个问题.首先,生成基准中包含的随机数据所需的时间是多少?

是的,它会的.所有的随机生成都应该懒散地进行.

为了检查是否发生这种情况,我在IO monad中编写了一个替代版本的数据生成器.我将基准列表与main(称为生成器)放在一起,用< - 提取结果,然后将其传递给基准函数.我发现性能没有差别.

这是预期的(如果我明白你的意思); randoms gen在需要之前(即在基准测试循环内),不会生成随机值.

有没有一种巧妙的方法在每个数据*函数中生成不同的随机数据?"整洁"意味着"没有使数据功能在IO中获取StdGen"?

您需要使用IO或者StdGen使用您提供的整数种子创建mkStdGen.

回覆.你的主要问题是如何从你的基准测试中获得pRNG的东西,你应该能够你的defaultMain (benchmarks g)东西之前完全评估随机输入,evaluate并且force喜欢:

import Control.DeepSeq(force)
import Control.Exception(evaluate)
myBench g = do randInputEvaled <- evaluate $ force $ dataFun g
               defaultMain [
                    bench "MyFun" $ nf benchFun randInputEvaled
                    ...
Run Code Online (Sandbox Code Playgroud)

在哪里force评估它的正常形式的论点,但这仍然会懒惰地发生.因此,为了在bench我们之外进行评估,我们使用evaluatemonadic测序.seq如果你想避免导入,你也可以做一些事情,比如调用你元组中每个列表的尾部等.

除非你需要在内存中保存大量的测试数据,否则这种情况应该可以正常工作.

编辑:如果你想从IO获取数据,这个方法也是一个好主意,比如从磁盘读取,并且不希望它与你的基准混合.

  • 谢谢.我今天做了很多测试,似乎标准自动处理懒惰和数据创建的问题.我在数据生成函数中使用了delayThread + unsafePerformIO来减慢它的速度.在估计运行基准测试所需的时间(估计大约110s)时,标准是错误的,但最终结果与我没有使用延迟相同.我注意到垃圾收集器结果扭曲了最终结果(-g标志用于救援!). (2认同)