Подтвердить что ты не робот

Как использовать Критерий для измерения производительности программ Haskell?

Я пытаюсь измерить производительность простой программы Haar DWT, используя структуру Criterion. (Это ошибочно медленно, но я оставлю это для другого вопроса). К сожалению, я не могу найти хорошую документацию в Интернете. Мои две основные проблемы:

  • Как передать данные с одного теста на другой? Я хочу, чтобы каждый этап программы.
  • Как работает выборка и избегайте ленивой оценки, повторно использующей предыдущие вычисления?

Этот источник относительно ограничен; первая функция getRandList создает список случайных чисел; haarStep преобразует входной сигнал в разности и суммы, а haarDWT вызывает первый и рекурсивные суммы. Я пытаюсь передать getRandList на haarDWT через ленивую оценку, но, возможно, мое использование неверно/не поддерживается. Тайминги, похоже, не имеют смысла.

{-# LANGUAGE ViewPatterns #-}

import Control.Arrow
import qualified Data.Vector.Unboxed as V
import System.Random
import Criterion.Main

invSqrt2 = 0.70710678118654752440

getRandList :: RandomGen g => g -> Int -> [Float]
getRandList gen 0 = []
getRandList gen n = v:rest where
    (v, gen') = random gen
    rest = getRandList gen' (n - 1)

haarStep :: V.Vector Float -> (V.Vector Float, V.Vector Float)
haarStep = (alternatingOp (-) &&& alternatingOp (+)) where
    alternatingOp op x = V.generate (V.length x `div` 2) (\i ->
        ((x V.! (2 * i)) `op` (x V.! (2 * i + 1))) * invSqrt2)

haarDWT :: V.Vector Float -> V.Vector Float
haarDWT [email protected](V.length -> 1) = xl
haarDWT (haarStep -> (d, s)) = haarDWT s V.++ d

main = do
    gen <- getStdGen
    inData <- return $ getRandList gen 2097152
    outData <- return $ haarDWT (V.fromList inData)

    defaultMain [
        bench "get input" $ nf id inData,
        bench "transform" $ nf V.toList outData
        ]
    writeFile "input.dat" (unlines $ map show inData)
    writeFile "output.dat" (unlines $ map show $ V.toList outData)

Наконец, я получаю сообщение об ошибке при попытке называть его -s 1; возможно, это всего лишь ошибка Criterion.

Main: ./Data/Vector/Generic.hs:237 ((!)): index out of bounds (1,1)

Спасибо заранее!

4b9b3361

Ответ 1

Опубликованный критерий неистово медленный... или он

Вы уверены, что это ошибочно? Вы трогаете (ну, звонок "nf" трогает) 2 миллиона штук в коробке - это 4 миллиона указателей. Вы можете назвать это ошибочным, если хотите, но проблема в том, что вы думаете, что вы измеряете по сравнению с тем, что вы действительно измеряете.

Обмен данными между контрольными метками

Обмен данными может осуществляться через частичное приложение. В моих тестах я обычно

let var = somethingCommon in
defaultMain [ bench "one" (nf (func1 somethingCommon) input1)
            , bench "two" (nf (func2 somethingCommon) input2)]

Предотвращение повторного использования во время ленивой оценки

Критерий позволяет избежать совместного использования, отделяя вашу функцию и ваш ввод. У вас есть подписи, такие как:

funcToBenchmark :: (NFData b) => a -> b
inputForFunc :: a

В Haskell каждый раз, когда вы применяете funcToBenchmark inputForFunc, он создает тон, который необходимо оценить. Совместное использование отсутствует, если вы не используете одно и то же имя переменной, как в предыдущем вычислении. Нет автоматических заметок - это похоже на общее недоразумение.

Обратите внимание на нюанс в том, что не используется. Мы не разделяем конечный результат, но общий вход. Если генерация входного сигнала - это то, что вы хотите проверить (т.е. GetRandList, в этом случае), то сравнивайте это, а не только функцию identity + nf:

main = do
    gen <- getStdGen
    let inData = getRandList gen size
        inVec = V.fromList inData
        size = 2097152
    defaultMain
      [ bench "get input for real" $ nf (getRandList gen) size
      , bench "get input for real and run harrDWT and listify a vector" $ nf (V.toList . haarDWT  . V.fromList . getRandList gen) size
      , bench "screw generation, how fast is haarDWT" $ whnf haarDWT inVec] -- for unboxed vectors whnf is sufficient

Интерпретация данных

Третий тест довольно поучителен. Давайте посмотрим, какой критерий распечатывается:

benchmarking screw generation, how fast is haarDWT
collecting 100 samples, 1 iterations each, in estimated 137.3525 s
bootstrapping with 100000 resamples
mean: 134.7204 ms, lb 134.5117 ms, ub 135.0135 ms, ci 0.950

Основанный на одном прогоне, Criterion думает, что потребуется 137 секунд, чтобы выполнить 100 образцов. Примерно через десять секунд это было сделано - что случилось? Ну, первый запуск заставил все входы (inVec), что было дорого. Последующие прогоны обнаруживают значение вместо thunk, и поэтому мы по-настоящему сравниваем haarDWT, а не StdGen RNG (который, как известно, мучительно медленный).