15

Criterion ライブラリを使用して、Haskell 関数のベンチマークを作成しました。現在、Haskell とパフォーマンスを比較するために C で同じアルゴリズムを実装しています。問題は、どうすれば確実に行うことができるかです。Criterion は、クロック呼び出しのオーバーヘッドを考慮したり、結果の統計分析を行ったりするなど、多くの凝った処理を行います。C 関数に必要な時間を測定するだけでは、Criterion によって返される結果と比較できないと思います。Criterion に関する彼の最初の投稿で、 Bryan O'Sullivan は次のように書いています。問題はどのようにですか?村主隆之氏による DFT の C 実装の比較スレッドを生成して実行可能ファイルを呼び出すことでHaskellを使用していますが、これにより多くの追加のオーバーヘッド(新しいスレッドの作成、アプリケーションの実行、stdioへの出力、およびそれからの読み取り)が追加され、結果が比類のないものになるのではないかと心配しています. FFI を使用することも検討しましたが、追加のオーバーヘッドによってこのような比較が不公平になるのではないかと懸念しています。

Criterion を使用して C を確実にベンチマークする方法がない場合、C ベンチマークへのどのアプローチをお勧めしますか? ここで SO に関するいくつかの質問を読みましたが、システム時間を測定できるさまざまな機能があるようですが、ミリ秒単位で時間を提供するか、呼び出しのオーバーヘッドが大きくなります。

4

1 に答える 1

13

FFI は、あまりオーバーヘッドを追加しないような方法で使用できます。次のプログラムを検討してください (完全なコードはこちらから入手できます)。

foreign import ccall unsafe "mean" c_mean :: Ptr CInt -> CUInt -> IO CFloat

main :: IO ()
main = do
  buf <- mallocBytes (bufSize * sizeOfCInt)
  fillBuffer buf 0
  m <- c_mean buf (fromIntegral bufSize)
  print $ realToFrac m

C 呼び出しは、次の Cmm にコンパイルされます。

s2ni_ret() { ... }
    c2qy:
        Hp = Hp + 12;
        if (Hp > I32[BaseReg + 92]) goto c2qC;
        _c2qD::I32 = I32[Sp + 4];
        (_s2m3::F32,) = foreign "ccall"
          mean((_c2qD::I32, PtrHint), (100,));

アセンブリは次のとおりです。

s2ni_info:
.Lc2qy:
        addl $12,%edi
        cmpl 92(%ebx),%edi
        ja .Lc2qC
        movl 4(%ebp),%eax
        subl $4,%esp
        pushl $100
        pushl %eax
        ffree %st(0) ;ffree %st(1) ;ffree %st(2) ;ffree %st(3)
        ffree %st(4) ;ffree %st(5)
        call mean

したがって、C インポートを としてマークし、unsafe測定前にすべてのマーシャリングを行うと、C 呼び出しは基本的に単なるインラインcall命令になります。これは、C ですべてのベンチマークを行っている場合と同じです。何もしません:

benchmarking c_nothing
mean: 13.99036 ns, lb 13.65144 ns, ub 14.62640 ns, ci 0.950
std dev: 2.306218 ns, lb 1.406215 ns, ub 3.541156 ns, ci 0.950
found 10 outliers among 100 samples (10.0%)
  9 (9.0%) high severe
variance introduced by outliers: 91.513%
variance is severely inflated by outliers

これは、私のマシンの推定クロック解像度 (~ 5.5 us) の約 400 分の 1 です。比較のために、100 個の整数の算術平均を計算する関数のベンチマーク データを次に示します。

benchmarking c_mean
mean: 184.1270 ns, lb 183.5749 ns, ub 185.0947 ns, ci 0.950
std dev: 3.651747 ns, lb 2.430552 ns, ub 5.885120 ns, ci 0.950
found 6 outliers among 100 samples (6.0%)
  5 (5.0%) high severe
variance introduced by outliers: 12.329%
variance is moderately inflated by outliers
于 2012-10-22T14:02:03.477 に答える