7

次のコード:

import Control.Exception
import Data.List

updateAverage :: (Fractional t) => (t, t) -> t -> (t, t)
updateAverage (old_value, old_counter) x =
    let new_counter = old_counter + 1
    in 
        assert(new_counter /= 0)
        old_value `seq` (old_value + (x - old_value) / new_counter, new_counter)

average values = fst (foldl' updateAverage (0.0, 0.0) values) -- version I

main = do
    let v = [1 .. 1000000]
    let a = average v
    putStrLn (show a)

関数ghc.exe -O3の定義を次のように置き換えると、高速になります(コンパイルオプション:)。average

average = fst . foldl' updateAverage (0.0, 0.0) -- version II

これの理由は何でしょうか?この2行の違いは基本的に構文だと思いました。2番目のバージョン(自由変数なしvalues)は、コンパイラーが最適化するのが簡単ですか?

おかしなことに、最適化せずにコンパイルすると、バージョンIが高速になります。

タイミング結果:

オプション:-O3

バージョンI:0.280秒バージョンII:0.212秒

オプション:(最適化なし)

バージョンI:0.42秒バージョンII:0.44秒

timeCygwinのシェルコマンドを使用して測定。

type = Doubleのタイミング結果:

ダブル:

オプション:-O3

バージョンI:0.22秒バージョンII ::0.212秒

オプション:(最適化なし)

バージョンI:0.34秒バージョンII:0.35秒

詳細:コンパイラを使用しています

> $ ghc -v Glasgow Haskell Compiler, Version 7.0.4, for Haskell 98,
> stage 2 booted by GHC version 6.12.2 Using binary package database:
> C:\Program Files\Haskell
> Platform\2011.4.0.0\lib\package.conf.d\package.cache wired-in package
> ghc-prim mapped to ghc-prim-0.2.0.0-e1f7c380581d61d42b0360d440cc35ed
> wired-in package integer-gmp mapped to
> integer-gmp-0.2.0.3-91607778cf3ae8f3948a50062b4f8479 wired-in package
> base mapped to base-4.3.1.0-f520cd232cc386346843c4a12b63f44b wired-in
> package rts mapped to builtin_rts wired-in package template-haskell
> mapped to template-haskell-2.5.0.0-7d9b1443ac5ab69e5ed705a487990deb
> wired-in package dph-seq not found. wired-in package dph-par not
> found. Hsc static flags: -static
> *** Deleting temp files: Deleting:
> *** Deleting temp dirs: Deleting: ghc.exe: no input files Usage: For basic information, try the `--help' option.
under Cygwin.*
4

1 に答える 1

3

ストリーム融合やループ融合で何かが起こっているのではないかと思います。おそらく、プレリュードの奥深くに埋め込まれた書き換えルールがあり、ある場合には発火するか、別の場合には発火しません。または、どれだけ速くなるかを言わないので、単にキャッシュ効果を確認している可能性があります。

あなたがもっと知りたいなら、釣りを学ぶ:

  • ghc -ddump-simpl実際に生成されているコードを確認して比較するために使用します。

  • valgrindを使用して、実行されている命令の数をカウントします。

他に何もないとしても、これらのツールは、より焦点を絞った詳細な質問をするのに十分な情報を提供します。

于 2012-03-16T15:02:41.993 に答える