GHCの並列ビルドが実用的になっていました
状況が変わったのを感じました
以前にこういうメモを書きました。 StackはGHCやCabalに並列ビルドのjobsオプションを伝えていませんが, 伝えたとしてもGHCの問題で全然速くならない - ncaq
以前の記事では実際に測ってみてGHCの-j
オプションは役に立たないことを確かめました。
しかし最近以下の記事を読みました。 GHC 9.8の新機能
これによると新しいGHCでは-jsem
オプションを実装することで、対応したCabalなどのビルドツールでパッケージ単位とモジュール単位の並列化の両方のジョブ数を制御出来るようになったようです。つまりGHCのモジュール単位の並列化に意味があることをアテにした実装がなされています。
ということは今のGHCのバージョンでもモジュール単位の並列化は有効に動くのではないかと考えました。
とりあえず計測あるのみです。
計測
現在の最新であるStackageのLTS 21が利用するghc-9.4.5を使って測定しました。 GHC 9.8系を使わなくても、以前からモジュール単位の並列化が意味を成すものになっているのであれば、これでも有効なはずです。
環境
- コンパイラ: GHC 9.4.5
- OS: Ubuntu 22.04.3 LTS(WSL2)
- CPU: Ryzen 9 7950X
- メモリ: 128GB
計測結果
デフォルトと並列化有効化の時でそれぞれ当然ですがcleanしてからビルドして、
time
のtotalの値を見ます。
実際に仕事で使うモジュール並列化の速度を計測したいため、依存ライブラリは事前にビルドしておきます。
仕事で今メインで触っているパッケージ
Stackを使っているのでpackage.yaml
のghc-options
に-j
を記載しました。
デフォルト
stack test --no-run-tests 167.03s user 6.98s system 101% cpu 2:51.65 total
-j
有効化
stack test --no-run-tests 315.04s user 47.82s system 324% cpu 1:51.75 total
pandoc
モジュールが非常に多いパッケージとして選びました。 Cabalを使いましたが、 Stackにも対応しているのでそちらで測るべきだったかもしれません。
デフォルト
cabal build 276.47s user 4.18s system 100% cpu 4:40.59 total
-j
有効化
cabal build --ghc-option='-j' 850.04s user 53.86s system 642% cpu 2:20.76 total
ビルドが高速化されました
仕事で使っているパッケージに関しても、モジュールが多いパッケージに関しても、ビルドが約2/3
程度には高速化されました。
早速含めてコミットすることにしました。
16コア32スレッドを使い切ってくれないのはモジュール同士の依存関係が絡み合ってるのと、一つのモジュールにたくさん書いてしまうのが横行しているからでしょう。 cycle importの解決はかなり面倒ですし、これまではモジュールを分けても並列ビルドによる高速化が期待出来なかったので、速度面では差分ビルドの高速化ぐらいしか分けるモチベーションがありませんでしたからね。
StackでもCabalと同じく-jsem
を実装しようとする動きはあるようです。
Support GHC's -jsem <sem>
initiative · Issue #6131 · commercialhaskell/stack
これが実装されればstack install
をglobalな環境向けに実行するときも、高速にビルドさせるのが容易になりそうです。これまでもモジュール単位では並列ビルドしてくれましたが、どうしてもpandocなどがモジュールたくさんで遅いという状態になっていたので今後の進展に期待です。他にもGTKなどのバインディングも大量の並列したモジュールが含まれるため期待できます。