2011-12-04 30 views
6

在基準函數Criterion之前如何強制評估函數的輸入?我正在嘗試對一些函數進行基準測試,但希望排除評估輸入thunk的時間。有問題的代碼使用unboxed vectors進行輸入,對於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輸入。標準測量低於 - 它測量大約〜400ns的用於這似乎包括用於輸入編譯時間以及每個功能:

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」基準,我拿到〜150ns的時間爲那一個了。

我從Criterion文檔瞭解到,它試圖避免延遲評估以獲得更準確的基準。這是有道理的,這裏並不是真正的問題。我的問題是如何構建shortv和intv輸入,以便在傳遞給bench函數之前已經對它們進行了評估。現在,我可以通過限制defaultMain一次只對一個函數進行基準測試來實現這一點(正如我剛纔所示),但這不是一個理想的解決方案。

EDIT1

還有別的東西與標準基準怎麼回事,它似乎只發生在Vector數組,而不是名單。如果我通過打印shortv和intv強制進行全面評估,那麼基準測量的時間仍然是〜400ns,而不是〜150ns。代碼更新如下:

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 

回答

3

你可以調用defaultMain運行基準測試之前使用evaluate。不知道它是否是最乾淨的解決方案,但它看起來像這樣:

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

測試與評估,如您所建議的,但它並沒有改變結果。我想這是因爲它評估表達式爲whnf,而不是nf。 – Sal

+2

我不認爲這可能是問題:例如, 'Int32'是'Data.Vector.Primitive.Vector Int32'的一種新類型,它只包含'Int'和'ByteArray'的嚴格字段。最後一個是圍繞原始'ByteArray#'的數據類型,我認爲這是嚴格的。但測試應該很簡單:只需將'evaluate'調用改爲打印總和即可。 –

+0

是的,你是對的。我在vector數組上使用print語句嘗試了forM_,並得到了相同的結果。還有其他事情正在發生,而且它對於Vector數組似乎非常特殊。當我最初使用列表編寫函數時,我沒有看到這個問題。 – Sal