elmのコンパイラがめっちゃ遅かったから速くした

*社内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
    ...
```

---

## 複雑なパターンマッチを取り除いたが
<h1><strong> 効果がなかった </strong></h1>
(いうほど複雑なパターンマッチなかった)

---

# 解決するためにコンパイラのメトリクスをとった
- 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)
```

---


<h1><strong>GCしすぎ！ """GC time  169.701s"""</strong></h1>

---

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
```

<h1><strong>効果がなかった..? """GC time  169.701s"""</strong></h1>

```
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)
```

---

<h1><strong>効果があった！ """GC time  4.076s"""</strong></h1>

```
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