2011-12-04 14 views
6

Criterionで関数のベンチマークを行う前に、関数の入力の評価を強制するにはどうすればよいですか?私はいくつかの機能をベンチマークしようとしていますが、入力サンクを評価する時間を除外したいと考えています。問題のコードはunboxed vectorsを入力に使用しますが、Intベクトルの場合はdeepseq'dできません。以下の例のコードスニペット:基準のベンチマーク前に関数入力の評価を強制する

-- 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の間に測定:ベンチマークコードの主要なセクションは以下のように変更された場合(第2ベンチ機能を除去することで)、今

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」ベンチマーク場合は、私が手に〜あまりにもその1つのための時間が150nsです。

私はCriterionのドキュメントから、より正確なベンチマークのために怠惰な評価を避けることを試みていることを知っています。それは理にかなっており、実際にはここでは問題にはなりません。私の質問は、どのようにshortvとintvの入力をビルド関数に渡す前に評価されるようにビルドするかです。今、私はこれを達成するために、defaultMainを一度に1つの関数のみをベンチマークするように制限します(私が上に示したように)。しかし、それは理想的な解決策ではありません。

EDIT1

あり基準のベンチマークでここで起こって何か他のものがあり、唯一のベクトル配列ではなく、リストに起こるようです。私がshortvとintvを出力して完全な評価を強制すると、ベンチマークではまだ時間が〜150nsではなく400nsと測定されます。コードは以下の更新:

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

あなたが提案したようにテストされていますが、結果は変更されませんでした。これは、nfではなく、whnfに式を評価するためです。 – Sal

+2

これは問題ではないと思います。 'Int32'は' Int.s'と 'ByteArray'の厳密なフィールドだけを含む' Data.Vector.Primitive.Vector Int32'を取り巻く新しい型です。最後のものはプリミティブ 'ByteArray#'の周りのデータ型です。これは厳しいと思います。しかし、テストは簡単でなければなりません。 'evaluate'呼び出しを、代わりに合計を出力するものに変更してください。 –

+0

はい、あなたは正しいです。私はベクトル配列のprint文でforMを試してみたところ、同じ結果が得られました。何か他のことが起こっており、ベクトル配列に非常に特有のようです。私は最初にリストを使って関数を書きましたが、この問題は見えませんでした。 – Sal

関連する問題