• 作成:

GHCのプロファイル機能がCabalのエラーで動かなかったことを解決しました

問題

stack bench --profileが失敗します。

動機

パフォーマンスチューニングを行いたい場合、当然まずは計測をすることになります。

Haskell(GHC)にはそれなりに良いプロファイラが付属しているため、まずはこれを使って計測をするのが早道だと思います。

既に他のメンバーによって最適化の数値を計測しやすくするため、 benchmarkstasty-benchによって実装されているため、このベンチマークで動く処理のプロファイルを取るのが早道でしょう。

期待される動作

stack bench --profileでプロファイル有効でベンチマークが動く。

実際の動作

--  While building package foo-0.1.0 (scroll up to its section to see the error) using:
      /home/ncaq/Desktop/foo/.stack-work/dist/x86_64-linux-tinfo6/Cabal-3.2.1.0/setup/setup --builddir=.stack-work/dist/x86_64-linux-tinfo6/Cabal-3.2.1.0 bench bar-bench "--benchmark-options=+RTS -p -RTS +RTS -T --nonmoving-gc"
    Process exited with code: ExitFailure 1

のように失敗する。

バージョン読み込み失敗問題はstack clean --fullで解決します

RIOを使っていて、 gitのHEADを見るからか、

/home/ncaq/Desktop/foo/app/Main.hs:28:5: fatal:
    cannot find object file ‘.stack-work/dist/x86_64-linux-tinfo6/Cabal-3.2.1.0/build/foo/foo-tmp/Paths_foo.dyn_o’
    while linking an interpreted expression

のようにバージョン読み込みに失敗することがありますが、これはstack clean --fullで解決します。

問題の本質

この問題はStackではなくCabalの問題で、 Profiling executables which use Template Haskell fails · Issue #5961 · haskell/cabal にissueが開かれています。

TemplateHaskellが絡むと問題が発生するようですね。

解決探索

issueに従って、 other-extensions: TemplateHaskell を書いていきましょう。

other-extensionsってなんだ…?

Document other-extensions in user guide · Issue #1517 · haskell/cabal によると使われる可能性のある拡張を指定できるらしい。いや書かなくても使えるのだがどういうことだろう。

まあ何にせよTemplateHaskellは実際に使っているのでトップレベルのother-extensionsに指定しましょう。同じくエラーになりますね… 本当はしたくないですがdefault-extensionsに指定してみますか。これで動くか確かめます。動かないですね…

おかしいなあ、他のプロジェクトではこれで回避してるのですが…

stack.yamlに書いてた記述が問題っぽかったです。

tasty-bench がメモリ使用量を測るためのオプションとして推奨していたので以下のように書いていたのですが、これが引っかかったようですね。

build:
  bench: false
  benchmark-opts:
    benchmark-arguments: "+RTS -T --nonmoving-gc"

Note that --nonmoving-gc cannot be used with -G1, profiling nor -c.

5.7. Running a compiled program — Glasgow Haskell Compiler 9.0.1 User's Guide

グエーちゃんとプロファイルとは併用できないとGHCの公式ガイドに書かれている。

よってこれも削除することでプロファイルが動くようになりました。

解決方法まとめ

  • other-extensions: TemplateHaskellを書く
  • --nonmoving-gcを消去する

の2つで今回は動かせるようになりました。

CabalとStackのレイヤーに阻まれたのか、 GHCのエラーメッセージがマトモに出なくて、色々探す苦労をすることになりました。