社内LTの資料(ほぼ)そのままなので雑な記事です
elmのコンパイラがめっちゃ遅かったから速くした
大筋
- これをやってみたというわけです-> https://medium.com/@antewcode/faster-elm-builds-e0669580ee67
- めっちゃelmを書いていたらビルドに260秒くらいかかってた
- 解決するためにコンパイラのメトリクスをとった
- GCに問題があったのでヒープサイズ変更した
- ビルドは40秒くらいになった。嬉しい。
elmを書いていたらビルドに260秒くらいかかってた
- 差分ビルドは変更するモジュールによるが、5秒 ~ 1分
- 変更モジュールの参照が多いほど時間は伸びる
- LOC2万5千くらい
- elmのコンパイラーにはバグがあってビルドが長くなるケースある
- 複雑なパターンマッチ (ex. タプル)があるとコンパイラがCPU100%食いつぶす
-> 複雑なパターンマッチをアプリケーションのコードから取り除く
複雑なパターンマッチをアプリケーションのコードから取り除く
compareMonth : Month -> Month -> Order
compareMonth m1 m2 =
case (m1, m2) of
(Jan, Jan) -> EQ
(Jan, _) -> LT
(Feb, Jan) -> GT
(Feb, Feb) -> EQ
(Feb, _) -> LT
(Mar, Jan) -> GT
...
複雑なパターンマッチをアプリケーションのコードから取り除く
compareMonth : Month -> Month -> Order
compareMonth m1 m2 =
case m1 of
(Jan) -> case m2 of
(Jan) -> EQ
(_) -> LT
(Mar) ->
(Feb) -> case m2 of
(Jan) -> GT
(Feb) -> EQ
(_) -> LT
(Mar) -> case m2 of
...
複雑なパターンマッチを取り除いたが
効果がなかった
(いうほど複雑なパターンマッチなかった)解決するためにコンパイラのメトリクスをとった
- elmのコンパイラにRTSオプション、ランタイムでのオプションを渡すとコンパイラの実行時リソースのメトリクスが取れる
- elmのコンパイラがhaskellによって作られるバイナリなのでできた
- 取れるメトリクス(一部)
INIT time 0.000s ( 0.001s elapsed)
MUT time 55.344s ( 40.095s elapsed)
GC time 169.701s ( 54.688s elapsed)
EXIT time 0.003s ( 0.020s elapsed)
Total time 225.050s ( 94.803s elapsed)
GCしすぎ! """GC time 169.701s"""
GCが多い -> heapサイズが足りてないんじゃない?メモリが全然使われてない
269 MB total memory in use (0 MB lost due to fragmentation)
haskellのRTS(ランタイムオプション)からheapサイズをコントロールする
-> そういう類のオプションがあった(厳密にそうなのかはわからない)
- 渡してみた
elm-make +RTS -A126M -RTS src/Main.elm
効果がなかった..? """GC time 169.701s"""
269 MB total memory in use (0 MB lost due to fragmentation)
- うまくオプションが渡ってなさそう。。。
- haskellのコンパイラ解説サイト様より
リンク時に-rtsoptsフラグを適切に設定していたなら、
プログラムを実行するときにRTSオプションを
コマンド行で与えることができる。
- elmのコンパイラは
-rtspots
が設定されていなかった(オワタ
- 厳密にいうと設定されてないわけじゃないけど使えない的な
コンパイラのコンパイルを試みた
- haskellのツール周りを調べてどうやらcabalというものでelmはコンパイルできるようだ -> 諦めた
- yak shavingにもほどが過ぎた
- GCC周りでエラー
- elmのコンパイラが依存しているhaskellライブラリ依存解決でエラー
インターネッツに再コンパイルされたコンパイラが落ちてた
- 自分と同じようなことをしている人がいた
- 心優しいその人がmac用のバイナリを例のオプションをつけてコンパイルしてくれていた
- 渡してみた
elm-make +RTS -A126M -RTS src/Main.elm
INIT time 0.001s ( 0.002s elapsed)
MUT time 39.714s ( 41.069s elapsed)
GC time 4.076s ( 2.170s elapsed)
EXIT time 0.003s ( 0.003s elapsed)
Total time 43.797s ( 43.244s elapsed)
効果があった! """GC time 4.076s"""
1209 MB total memory in use (0 MB lost due to fragmentation)
- メモリもふんだんに使われている
GC time: 169.701s -> 4.076s
Total time: 225.050s -> 43.797s
- GC時間は40倍短く
- トータル6倍速く
結論
- elmのコンパイラをrtsフラグ有効にしてコンパイルし直したやつ、またはhttps://medium.com/@antewcode/faster-elm-builds-e0669580ee67 で配布してくれているやつを使いつつRTSオプションでメモリいっぱい使うようにしたら速くなることもある。
ちなみに
- 次のバージョンのelmコンパイラではRTSオプションを標準で渡せるのでコンパイラのコンパイルはいらない(はず)
追記
- 0.19でRTSオプションが渡せるようになってました。
- 0.19ではRTSオプション気にしなくても超早くなりました。
参考url
elmのビルド速くしたぜ記事:
https://medium.com/@antewcode/faster-elm-builds-e0669580ee67
haskellのランタイムオプション説明してくれているページ:
: http://www.kotha.net/ghcguide_ja/7.6.2/runtime-control.html