15

Criterionフレームワークを使用して単純なHaarDWTプログラムのパフォーマンスを測定しようとしています。(誤って遅いですが、別の質問に残しておきます)。残念ながら、Web上で適切なドキュメントを見つけることができません。私の2つの主な問題は

  • あるベンチマークから別のベンチマークにデータを渡すにはどうすればよいですか?プログラムの各段階の時間を計りたいです。
  • サンプリングはどのように機能し、以前の計算を再利用する遅延評価を回避しますか?

このソースは比較的簡素化されています。最初の関数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 xl@(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最後に、 ;で呼び出そうとするとエラーが発生します。多分これは単なる基準のバグです。

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

前もって感謝します!

4

1 に答える 1

10

投稿されたベンチマークは非常に遅いです...それともそれですか

間違いですか?あなたは200万のボックス化された要素に触れています(まあ、「nf」呼び出しは触れています)-それは400万のポインタです。必要に応じてこれを誤って呼び出すこともできますが、問題は、実際に測定しているものと比較して、測定していると思うものにすぎません。

ベンチマーク間でのデータの共有

データ共有は、部分適用によって実現できます。私のベンチマークでは、私は一般的に持っています

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

遅延評価が存在する場合の再利用の回避

Criterionは、関数と入力を分離することで共有を回避します。次のような署名があります。

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

データの解釈

3番目のベンチマークはかなり有益です。どの基準が出力されるかを見てみましょう。

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

1回の実行に基づいて、Criterionは、100サンプルを実行するのに137秒かかると考えています。約10秒後にそれが行われました-何が起こったのですか?さて、最初の実行はすべての入力(inVec)を強制しましたが、これは高価でした。haarDWTその後の実行では、サンクではなく値が検出されたため、StdGenRNG(非常に遅いことが知られている)ではなく、真にベンチマークを実行しました。

于 2011-07-09T23:17:37.403 に答える