Принудительная оценка ввода функции перед сравнительным анализом в Критерии - PullRequest
6 голосов
/ 05 декабря 2011

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

-- V is Data.Vector.Unboxed
shortv = V.fromList [1..10] :: V.Vector GHC.Int.Int16
intv = V.fromList [1..10] :: V.Vector GHC.Int.Int32

main :: IO ()
main = defaultMain [
          bench "encode ShortV" $ whnf encodeInt16V shortv
          ,bench "encode IntV" $ whnf encodeInt32V intv
       ]

Критерий критерия включает в себя время для создания shortv и intv входов при тестировании вышеупомянутых функций. Критерии измерений приведены ниже - она ​​измеряет около 400 нс для каждой функции, которая, по-видимому, включает время сборки для входных данных:

benchmarking encode ShortV
mean: 379.6917 ns, lb 378.0229 ns, ub 382.4529 ns, ci 0.950
std dev: 10.79084 ns, lb 7.360444 ns, ub 15.89614 ns, ci 0.950

benchmarking encode IntV
mean: 392.2736 ns, lb 391.2816 ns, ub 393.4853 ns, ci 0.950
std dev: 5.565134 ns, lb 4.694539 ns, ub 6.689224 ns, ci 0.950 

Теперь, если основной раздел кода тестов изменен на нижний (путем удаления функции второго бенчмарка):

main = defaultMain [
          bench "encode ShortV" $ whnf encodeInt16V shortv
       ]

shortv Ввод, кажется, оценивается до того, как будет проверена функция encodeInt16V. Это действительно желаемый вывод для меня, потому что этот тест измеряет время выполнения функции, исключая время для создания ввода. Критерий вывода ниже:

benchmarking encode ShortV
mean: 148.8488 ns, lb 148.4714 ns, ub 149.6279 ns, ci 0.950
std dev: 2.658834 ns, lb 1.621119 ns, ub 5.184792 ns, ci 0.950

Точно так же, если я бенчмаркирую только эталонный тест "кодировать IntV", я тоже получу ~ 150 нс времени.

Из документации Criterion я знаю, что она пытается избежать ленивых вычислений для более точного сравнения. Это имеет смысл, и на самом деле это не проблема. Мой вопрос заключается в том, как мне построить входы shortv и intv, чтобы они уже были оценены перед передачей в стендовую функцию. Прямо сейчас я могу сделать это, ограничив defaultMain для тестирования только одной функции за раз (как я только что показал выше), но это не идеальное решение.

EDIT1

В тесте Criterion происходит что-то еще, и, похоже, это происходит только в массиве Vector, а не в списках. Если я выполню полную оценку, напечатав shortv и intv, тест все равно измеряет время как ~ 400 нс, а не ~ 150 нс. Обновление кода ниже:

main = do
  V.forM_ shortv $ \x -> do print x
  V.forM_ intv $ \x -> do print x
  defaultMain [
          bench "encode ShortV" $ whnf encodeInt16V shortv
          ,bench "encode IntV" $ whnf encodeInt32V intv
       ]

Выход критерия (также имеет выбросы 158,4%, что кажется неправильным):

estimating clock resolution...
mean is 5.121819 us (160001 iterations)
found 253488 outliers among 159999 samples (158.4%)
  126544 (79.1%) low severe
  126944 (79.3%) high severe
estimating cost of a clock call...
mean is 47.45021 ns (35 iterations)
found 5 outliers among 35 samples (14.3%)
  2 (5.7%) high mild
  3 (8.6%) high severe

benchmarking encode ShortV
mean: 382.1599 ns, lb 381.3501 ns, ub 383.0841 ns, ci 0.950
std dev: 4.409181 ns, lb 3.828800 ns, ub 5.216401 ns, ci 0.950

benchmarking encode IntV
mean: 394.0517 ns, lb 392.4718 ns, ub 396.7014 ns, ci 0.950
std dev: 10.20773 ns, lb 7.101707 ns, ub 17.53715 ns, ci 0.950

1 Ответ

3 голосов
/ 05 декабря 2011

Вы можете использовать evaluate перед вызовом defaultMain для запуска тестов. Не уверен, что это самое чистое решение, но оно будет выглядеть так:

main = do
  evaluate shortv
  evaluate intv
  defaultMain [..]
...