我使用criterion对我的Haskell代码进行基准测试。我正在做一些需要随机数据的繁重计算。我已经像这样编写了我的主要基准测试文件:
main :: IO ()
main = newStdGen >>= defaultMain . benchmarks
benchmarks :: RandomGen g => g -> [Benchmark]
benchmarks gen =
[
bgroup "Group"
[
bench "MyFun" $ nf benchFun (dataFun gen)
]
]我将它们的基准测试和数据生成器放在不同的模块中:
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)这是可行的,但我有两个顾虑。首先,生成随机数据所需的时间是否包含在基准测试中?我找到了a question that touches on that subject,但老实说,我无法将它应用到我的代码中。为了检查是否发生这种情况,我编写了一个包含在IO monad中的数据生成器的替代版本。我使用main放置基准测试列表,调用生成器,使用<-提取结果,然后将其传递给基准测试函数。我看不出性能有什么不同。
我的第二个关注点与生成随机数据有关。现在,生成器一旦创建就没有更新,这导致在一次运行中生成相同的数据。这不是一个大问题,但如果能做好就好了。有没有一种巧妙的方法来在每个data*函数中生成不同的随机数据?“整洁”意味着“不需要让数据函数在IO中获取StdGen”?
编辑:正如下面的评论中所指出的,我并不真正关心数据的随机性。对我来说重要的是,生成数据所需的时间不包括在基准测试中。
发布于 2012-10-15 21:37:37
这是可行的,但我有两个顾虑。首先,生成随机数据所需的时间是否包含在基准测试中?
是的会的。所有的随机生成都应该是懒惰的。
为了检查是否发生这种情况,我编写了一个包含在IO monad中的数据生成器的替代版本。我使用main放置基准测试列表,调用生成器,使用<-提取结果,然后将其传递给基准测试函数。我看不出性能有什么不同。
这是意料之中的(如果我理解你的意思);来自randoms gen的随机值只有在需要时才会生成(即在您的基准循环中)。
有没有一种巧妙的方法来在每个数据*函数中生成不同的随机数据?“整洁”意味着“不需要让数据函数在IO中获取StdGen”?
您需要在IO中,或者使用您提供的整数种子和mkStdGen创建一个StdGen。
Re.您的主要问题是应该如何将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
...其中force将其参数求值为标准形式,但这仍然会延迟发生。因此,为了让它在bench之外进行评估,我们使用evaluate来利用一元排序。如果你想避免导入,你也可以在元组中的每个列表的尾部调用seq,等等。
这种事情应该可以很好地工作,除非您需要在内存中保存大量的测试数据。
EDIT:如果您想从IO中获取数据,比如从磁盘读取数据,并且不想将其混入到您的基准测试中,则此方法也是一个好主意。
发布于 2012-10-16 03:11:37
您可以尝试从磁盘文件中读取随机数据。(实际上,如果您使用的是类Unix操作系统,您甚至可以使用/dev/urandom。)
但是,根据您需要的数据量,I/O时间可能会使计算时间相形见绌。这取决于你需要多少随机数据。
(例如,如果您的基准测试读取随机数并计算它们的总和,它将是I/O受限的。如果您的基准测试读取一个随机数并仅根据该数进行一些巨大的计算,则I/O几乎不会增加任何开销。)
https://stackoverflow.com/questions/12896235
复制相似问题