Создание нескольких критериев критериев одновременно

Этот код компилируется и запускается без проблем:

module Main where

import Criterion.Main

main :: IO ()
main =
  defaultMain
    [env (return $ [1,2])
         (\is ->
            bgroup "group" (benchmarks is))]

timesTwo :: Int -> Int
timesTwo i = 2 * i

benchmarks :: [Int] -> [Benchmark]
benchmarks is = [ bench "foo" $ nf timesTwo (is !! 0)
                , bench "foo" $ nf timesTwo (is !! 1) ]

Тем не менее, если я изменю benchmarks функция выглядеть

benchmarks :: [Int] -> [Benchmark]
benchmarks is = map (\i -> bench "foo" $ nf timesTwo i) is

это все еще компилируется, но я получаю эту ошибку времени выполнения:

ghci> main
*** Exception: Criterion atttempted to retrieve a non-existent environment!
        Perhaps you forgot to use lazy pattern matching in a function which
        constructs benchmarks from an environment?
        (see the documentation for `env` for details)

Как мне решить это?

Как вы можете видеть, моя цель состоит в том, чтобы отобразить список из полученных из среды, чтобы превратить его в список Benchmark с, что я могу использовать с критерием.

Примечание: в конечном итоге я хочу использовать больше элементов, чем просто два, поэтому здесь я не хочу кортежи.

2 ответа

Для бенчмаркинга разных размеров я обычно делаю что-то вроде этого:

module Main (main) where

import Criterion.Main
import System.Random
import Control.Monad

import qualified Data.List
import qualified Data.Sequence

int :: Int -> IO Int
int n = randomRIO (0,n)

benchAtSize :: Int -> Benchmark
benchAtSize n =
    env (replicateM n (int n)) $
    \xs ->
         bgroup (show n)
           [ bench "Data.List"     $ nf Data.List.sort xs
           , bench "Data.Sequence" $ nf (Data.Sequence.sort . Data.Sequence.fromList) xs
           ]

main :: IO ()
main = defaultMain (map benchAtSize [100, 1000, 10000])

env полезен для обеспечения сравнения двух разных функций в одном и том же образце и не предназначен для вычисления всего набора данных перед запуском тестов. Кроме того, потому что все данные, созданные env хранится в памяти во время бенчмаркинга всего, что находится в его области, вы хотите минимизировать его настолько, насколько это возможно, чтобы уменьшить накладные расходы при бенчмаркинге.

env очень требователен со строгостью. Вы не можете использовать это здесь. Структура бенчмарков, созданных под env не может зависеть от окружающей среды. То есть среда может использоваться кодом, который тестируется, но способ, которым сами тесты организованы, названы и т. Д., Не могут использовать его. Это потому что criterion будет иногда проходить _|_ вместо реальной среды, когда он хочет просто проверить структуру тестов, не выполняя их. Когда вы используете !!организация тестов указывается от руки и остается неизменной, даже если is = _|_:

benchmarks _|_ = [ bench "foo" $ nf timesTwo _|_ -- _|_ !! n = _|_; nf is not strict
                 , bench "foo" $ nf timesTwo _|_ ] -- "bench"s are still there

Но map ломает это:

benchmarks _|_ = map _etc _|_
               = case _|_ of -- definition of map
                      [] -> []
                      x:xs -> _etc x : map _etc xs
               = _|_ -- benchmark structure gone

Ваша лучшая ставка просто не использует env:

main = do is <- _ -- however you calculate is
          defaultMain $ bgroup "group" $ benchmark is
Другие вопросы по тегам