続:Haskellのfibが遅い件
![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
@tanakh ヒント: http://d.hatena.ne.jp/camlspotter/20100128/1264678903 [要出典]
2010-07-20 18:44:25![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
ものすごい長いサンクの連鎖を評価している最中は全部のサンクがスタックに乗った感じになるので、実はスタックの上の人たちは世代とか関係なく全部なめてしまうので、そういう時に限りやたらGCに時間がかかるのではなかろうか!!!という閃きを得た。検証せず寝る #haskell_fib
2010-07-21 03:10:20![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
#haskell_fib やっぱりスタックは全スキャンしてる (rts/sm/GC.c→rts/Capabitiliy.c:markSomeCapabilities→...→rts/sm/Scav.c:scavangeTSO, scavenge_stack)
2010-07-21 10:30:10![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
#haskell_fib +RTS -AxxxK でマイナGCヒープのサイズをどう変えても、前半(スタック短)と後半(スタック長)で1回辺りのマイナGC時間の"差"がほぼ一定で、この差は入力Nに対しO(N)。後半のみ、マイナGCでも全生存オブジェクト数に比例する時間がかかってる。
2010-07-21 10:35:57![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
ghc で作るプログラムは、メモリオプションが複数。「トレードオフすれ」、これを『Haskell は』というのはアレだと思います : http://haskell.org/ghc/docs/6.12.1/html/users_guide/runtime-control.html
2010-07-21 10:39:46![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
6.12.3 が stable release なのに、6.12.1 のドキュメントをうっかり貼ってしまった
2010-07-21 10:41:02![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
#ghc_fib マイナGCは連続allocationが起きてると一定間隔(デフォルトでは512KB毎)で動くので、つまり後半ではN/512K回動くので、1回当たりO(N)時間かかるなら合計ではO(N^2)時間かかっている(ただし1/512Kという小さい係数)という状況
2010-07-21 10:41:15![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
#ghc_fib というわけで、fib::[Int] = 1:1:zipWith fib (tail fib) にかかる時間がO(N)になってない挙動は http://bit.ly/9S44AQ (に加えて http://bit.ly/dy2MsG ) で説明がつくと思う。
2010-07-21 10:43:33![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
#ghc_fib なんだか話を聞いた瞬間0.01秒でまずそれを考えろ俺という感じの説明だった。 / fib::[Integer] の場合は遅くなる現象は手元で再現できてないのでわからない。32bitsと64bitsで違ったりとかだろうか…
2010-07-21 10:49:26![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
@nishio ひーすみませんもう一度実験やりなおしてみたらこっちの32bit機でも遅くなりました。http://twitter.com/kinaba/status/16819284827 この時は 6.10.1 で、今 6.12.3 なのでその差だろうか…orz
2010-07-21 13:32:43![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
ついでにカピバラさんのデータを「300000からわずかにO(n ^ 2)を外れる」と書いているからその手前まででフィッティングしたらO(n ^ 2.4)だった件
2010-07-21 14:43:04![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
6.10.1との差は多分これだなー http://hackage.haskell.org/trac/ghc/ticket/2747 …so a program that allocates all or mostly large objects can use… #ghc_fib
2010-07-21 15:53:06![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
fib の話ですが、とりあえず、GHC が現在対応している最適化レベルは -O2 までですよ [http://bit.ly/bE1to8 ]、あと正格性解析が有効になるのは -O オプションからです [http://bit.ly/cXdkyQ ] 、とだけ。 #ghc_fib
2010-07-21 16:26:22![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
@kinaba 6.10.2でそれが入ったということなら、僕の環境は6.10.4だったのでありえます RT http://hackage.haskell.org/trac/ghc/ticket/2747
2010-07-21 17:00:08![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
@nishio 手元に6.10.1と6.10.2をインストールし直して試してみたところ6.10.2は以降のバージョンと変わらない動きをするので、このfixが理由かどうかはともかく、6.10.1→6.10.2 が境界なのは確かなようです。
2010-07-21 17:08:45![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
@nishio Integerのfibも7**nも、+RTS -sしてみるとGCの回数が線形では抑えられない感じに増えてますね(細かい率は調べてませんが…)。マイナGCヒープをすぐ埋め尽くすような巨大オブジェクトが大量に生成される状態はプログラマが注意せよ、ってことじゃないかなあ
2010-07-21 17:21:12![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
#ghc_fib は「スタックが凄く深い所で大量にアロケーション&GCすると大変」の一言でマトメたい気分。@nishio さんのpow http://bit.ly/abRZR4 も末尾再帰ならGCの回数は変わらないけど実行時間は段違い。他の言語についてはshinhさん頼みである。
2010-07-21 17:58:49