简体   繁体   English

初始化标准中的基准并从结果中排除初始化时间

[英]Initialize benchmark in criterion and exclude initialization time from results

I need to benchmark some code inside IO , and criterion supports that pretty well. 我需要对IO一些代码进行基准测试,并且标准支持非常好。 But I want to perform few initialization steps (different for each benchmark). 但我想执行一些初始化步骤(每个基准测试都不同)。 The naive approach: 天真的方法:

main = defaultMain
  [ bench "the first" $ do
      initTheFirst
      theFirst
      cleanUpTheFirst
  , bench "the second" $ do
      initTheSecond
      theSecond
      cleanUpTheSecond
  ]

But it performs initialization and cleanup for every benchmark run (100 times by default) and includes initialization time to final results. 但它会为每个基准测试运行执行初始化和清理(默认情况下为100次),并包括最终结果的初始化时间。 Is it possible to exclude initialization time? 是否可以排除初始化时间?

ADDED: The code uses global state (mongodb actually), so I can't prepare two initial states simultaneously. ADDED:代码使用全局状态(实际上是mongodb),所以我无法同时准备两个初始状态。

Here is a solution using custom main as suggested by argiopeweb: 这是使用argiopeweb建议的自定义main的解决方案:

import Control.Monad
import Control.Monad.IO.Class
import Control.Concurrent
import Criterion
import Criterion.Config
import Criterion.Monad
import Criterion.Environment

main :: IO ()
main = myMain [
  (initTheFirst, theFirst),
  (initTheSecond, theSecond)
  ]

initTheFirst :: IO ()
initTheFirst = do
  putStrLn "initializing the first"
  threadDelay 1000000

theFirst :: Benchmark
theFirst = bench "the first" $ do
  return () :: IO ()

initTheSecond :: IO ()
initTheSecond = do
  putStrLn "initializing the second"
  threadDelay 1000000

theSecond :: Benchmark
theSecond = bench "the second" $ do
  return () :: IO ()

myMain :: [(IO (), Benchmark)] -> IO ()
myMain benchmarks = withConfig defaultConfig $ do
  env <- measureEnvironment
  forM_ benchmarks $ \(initialize, benchmark) -> do
    liftIO $ initialize
    runAndAnalyse (const True) env benchmark

The output: 输出:

warming up
estimating clock resolution...
mean is 1.723574 us (320001 iterations)
found 1888 outliers among 319999 samples (0.6%)
  1321 (0.4%) high severe
estimating cost of a clock call...
mean is 43.45580 ns (13 iterations)
found 2 outliers among 13 samples (15.4%)
  2 (15.4%) high severe
initializing the first

benchmarking the first
mean: 7.782388 ns, lb 7.776217 ns, ub 7.790563 ns, ci 0.950
std dev: 36.01493 ps, lb 29.29834 ps, ub 52.51021 ps, ci 0.950
initializing the second

benchmarking the second
mean: 7.778543 ns, lb 7.773192 ns, ub 7.784518 ns, ci 0.950
std dev: 28.85100 ps, lb 25.59891 ps, ub 32.85481 ps, ci 0.950

You can see that init* functions are called only once and don't affect benchmarks results. 您可以看到init*函数只被调用一次,不会影响基准测试结果。

Three real options I can see here. 我可以在这里看到三个真正的选择。 Either initialize and cleanup before and after: 在之前和之后进行初始化和清理:

main = do
  initTheFirst
  initTheSecond

  defaultMain
    [ bench "the first" theFirst
    , bench "the second" theSecond
    ]

  cleanUpTheFirst
  cleanUpTheSecond

Or, if that isn't possible, also benchmark your cleanup and initialization processes and modify your benchmark times accordingly. 或者,如果不可能,还要对清理和初始化过程进行基准测试,并相应地修改基准时间。

Alternatively, you could forego using the provided defaultMain and instead roll your own using the lower-level functions provided by Criterion. 或者,您可以放弃使用提供的defaultMain ,而是使用Criterion提供的较低级别函数自行滚动。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM