この質問に出くわしました 、フィボナッチ数の計算に関するさまざまなコンパイラのパフォーマンスを素朴な方法で比較しました。
Haskell でこれを実行して、C と比較してみました。
C コード:
#include <stdio.h>
#include <stdlib.h>
int fib (int n) {
if (n < 2) return 1;
return fib (n-1) + fib (n-2);
}
int main (int argc, char* argv[]) {
printf ("%i\n", fib (atoi(argv[1])));
return 0;
}
結果:
> gcc -O3 main.c -o fib
> time ./fib 40
165580141
real 0m0.421s
user 0m0.420s
sys 0m0.000s
ハスケル:
module Main where
import System.Environment (getArgs)
fib :: Int -> Int
fib n | n < 2 = 1
| otherwise = fib (n-1) + fib (n-2)
main = getArgs >>= print . fib . read . head
結果:
> ghc -O3 -fllvm -optlo-O3 Main.hs -o fib
> time ./fib 40
165580141
real 0m1.476s
user 0m1.476s
sys 0m0.000s
プロファイリング
> ghc -O3 -fllvm -optlo-O3 -prof -auto-all -caf-all -rtsopts Main.hs -fforce-recomp -o fib
> ./fib 40 +RTS -prof
fib
100% の時間と割り当てが必要であることがわかりますが、当然のことです。ヒープのプロファイルをいくつか取りましたが、それらが何を意味するのかわかりません:
> ./fib 40 +RTS -hc
> ./fib 40 +RTS -hd
私の質問: この Haskell プログラムのパフォーマンスを C に近づけるために、私の側からできることはありますか? それとも、このマイクロベンチマークで GHC がたまたま速度を低下させる方法なのですか? (フィブを計算するための漸近的に高速なアルゴリズムを求めているわけではありません。)
どうもありがとうございました。
[編集]
ghc -O3
この場合よりも高速であることが判明しましたghc -O3 -fllvm -optlo-O3
。しかしoptlo-block-placement
、LLVM バックエンドには明らかな違いがありました。
> ghc -O3 Main.hs -o fib -fforce-recomp
> time ./fib 40
165580141
real 0m1.283s
user 0m1.284s
sys 0m0.000s
> ghc -O3 -fllvm -optlo-O3 -o fib -fforce-recomp
> time ./fib 40
165580141
real 0m1.449s
user 0m1.448s
sys 0m0.000s
> ghc -O3 -fllvm -optlo-O3 -optlo-block-placement -o fib -fforce-recomp
> time ./fib 40
165580141
real 0m1.112s
user 0m1.096s
sys 0m0.016s
私がこれを調査したかった理由は、このプログラムでは C と OCaml の両方が Haskell よりも大幅に高速だったからです。私はそれを受け入れることができず、できる限りのことをすでに行っていることを確認するためにもっと学びたいと思っていました:D
> ocamlopt main.ml -o fib
> time ./fib 40
165580141
real 0m0.668s
user 0m0.660s
sys 0m0.008s