Reputation: 34041
I wanted to do some profiling on a Haskell application so in my hpack I added some ghc-options
:
example-executable:
source-dirs: src
main: Main.hs
ghc-options:
- -O2
- -prof
- -fprof-auto
- -rtsopts
that resulted in this error:
[ 6 of 19] Compiling Model.Server ( src/Model/Server.hs, dist/build/discord-app-prof/discord-app-prof-tmp/Model/Server.o )
<no location info>: error:
src/Model/Server.hs:125:13: fatal:
Cannot load -prof objects when GHC is built with -dynamic
To fix this, either:
(1) Use -fexternal-interpreter, or
(2) Build the program twice: once with -dynamic, and then
with -prof using -osuf to set a different object file suffix.
Where is this -dynamic
coming from? I don't recall ever running into this issue before when profiling previously which is also strange. Also it's confusing when it says "GHC is built with -dynamic" - surely GHC is not being built here but the haskell executable?
I'm using GHC 9.0.2
Upvotes: 1
Views: 148
Reputation: 29193
First of all, -fprof-auto
is a bad idea. Every time I've used it or seen anyone use it, it gives wrong results. Profiling requires tagging code with cost centers, but cost centers inhibit many optimizations. You end up measuring code that is different from what actually executes on a normal run. (Code that's actually fast can appear much slower, so your optimization priorities will be mixed up.) I strongly recommend picking a different profiling option, or writing SCC
annotations yourself. Perhaps you can try the new -fprof-late
(though this requires GHC 9.4.1).
-dynamic
is the default because dynamic linking is the default on your OS (as it is on all the popular PC OSs). "GHC is built with -dynamic
" means exactly that; the GHC binaries you're using were (in the past, before you downloaded them or perhaps when you built them yourself) built with -dynamic
. You of course aren't rebuilding GHC now.
Profiling requires not just your own code be built with -prof
, but that all dependencies also be built with -prof
. This is something the build system (Cabal) needs to orchestrate, to create and then point GHC at the correct files. You can't just throw -prof
into ghc-options
. In the very simplest case, if you were using bare cabal-install
, you just need to add the following to cabal.project.local
. I believe cabal configure --enable-profiling --profiling-detail=late
would write out such a file too. You do not put -prof -fprof-late
into ghc-options
.
profiling: True
profiling-detail: late
The next cabal build
of the project will (re)build all dependencies as needed with profiling. I believe Cabal also uses -dynamic-too
to get the -dynamic
and -prof
versions of the objects simultaneously and avoids the GHC error you saw by pointing e.g. ghci
at the -dynamic
objects when requested. You can control the profiling detail in dependencies through cabal.project.local
, too. (The way it stands, this file applies a default of -fprof-auto-exported
to all dependencies.)
Note that the .cabal
file wasn't touched. In the Cabal model, profiling is not part of the package description. Profiling is, after all, not part of the package content. Profiling is just a special way of building the package. (I note that you have -O2
in ghc-options
too. This is also anti-Cabal. The correct way to handle that is to put optimization: 2
into cabal.project.local
, probably under a package *
stanza to apply it to all dependencies as well as the current package.) The only option that should be in ghc-options
out of those you have listed is -rtsopts
.
I don't use hpack, but it looks to me that it only generates the .cabal
file (i.e. it just describes the package). As (reiterating) profiling and optimization are not properties of the package but properties of the build, you don't do anything to your hpack configuration to use them. You just write the appropriate cabal.project.local
and use that besides the .cabal
generated by hpack. I'm not sure what complications Nix adds here.
NB: There is a distinction between build configuration that should ship with the package and configuration local to the developer. The former goes in cabal.project
, the latter into cabal.project.local
. In order for cabal.project.local
to be processed correctly, you may need a trivial cabal.project
that contains simply packages: .
.
Upvotes: 4
Reputation: 34041
A quick solution was to change my default.nix
, the -dynamic
is probably being set as a default somewhere:
- myHaskellPackages.callCabal2nix "HaskellNixCabalStarter" (src) {}
+ myHaskellPackages.callCabal2nixWithOptions "HaskellNixCabalStarter" (src) "--enable-profiling" {}
As mentioned here: How can I enable Haskell profiling when using Nix's callCabal2nix
Upvotes: 0