Инициализировать тест по критерию и исключить время инициализации из результатов.
Мне нужно тестировать некоторый код внутри IO
и критерий поддерживает это довольно хорошо. Но я хочу выполнить несколько шагов инициализации (разных для каждого теста). Наивный подход:
main = defaultMain
[ bench "the first" $ do
initTheFirst
theFirst
cleanUpTheFirst
, bench "the second" $ do
initTheSecond
theSecond
cleanUpTheSecond
]
Но он выполняет инициализацию и очистку для каждого запуска теста (по умолчанию 100 раз) и включает время инициализации до конечных результатов. Можно ли исключить время инициализации?
ДОБАВЛЕНО: код использует глобальное состояние (на самом деле mongodb), поэтому я не могу подготовить два начальных состояния одновременно.
2 ответа
Три реальных варианта я вижу здесь. Инициализируйте и очистите до и после:
main = do
initTheFirst
initTheSecond
defaultMain
[ bench "the first" theFirst
, bench "the second" theSecond
]
cleanUpTheFirst
cleanUpTheSecond
Или, если это невозможно, также проведите сравнительный анализ процессов очистки и инициализации и соответствующим образом измените время тестирования.
Кроме того, вы можете отказаться от использования defaultMain
и вместо этого бросайте свои собственные, используя функции более низкого уровня, предоставляемые Criterion.
Вот решение, использующее пользовательский main как предложено argiopeweb:
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
Выход:
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
Ты это видишь init*
функции вызываются только один раз и не влияют на результаты тестов.