How do I tell stack
to build my executable and all its dependencies with -prof
?
Simply adding it to ghc-options
in the .cabal
file is not enough, because it only tries to build the executable with profiling enabled, which fails.
To build with profiling enabled:
stack build --profile
You may need to run stack clean
first, but this should be fixed in Stack 1.5.0.
To profile:
stack exec --profile -- <your program> +RTS <profiling options>
where for <profiling options>
you might want -p
for time profiling or -h
for memory profiling. For time profiling, the profile appears in ./<your program>.prof
, and for memory profiling, the profile appears in ./<your program>.hp
.
See GHC profiling documentation for more profiling options.
Due to a long standing Stack issue, switching between profiling and non-profiling builds can cause a lot of unnecessary rebuilding of local packages and extra-deps
. To work around this, you can use separate build caches for your profiling and non-profiling builds. For example, where you use stack <cmd>
for non profiling you can use
stack --work-dir .stack-work-profile --profile <cmd>
for a profiling version of <cmd>
. This uses a separate cache in .stack-work-profile
for profiling artifacts, whereas non profiling artifacts will be preserved in the default .stack-work
cache.
To build with profiling enabled:
stack build --executable-profiling --library-profiling --ghc-options="-fprof-auto -rtsopts"
To profile:
stack exec -- <your program> +RTS <profiling options>
Suppose you have a package called test
with a single executable test
defined by main
here:
module Main where main :: IO () main = do print $ foo 0 foo :: Int -> Int foo x = fooSub (x+1) where fooSub x = bar (x+1) bar :: Int -> Int bar x = barSub (x+1) where barSub x = barSubSub (x+1) where barSubSub x = x+1
then doing stack build --profile && stack exec -- test +RTS -p
will produce a file ./test.prof
which includes
individual inherited COST CENTRE MODULE SRC no. entries %time %alloc %time %alloc [... many lines omitted ...] main Main src/Main.hs:(4,1)-(5,15) 97 0 0.0 0.0 0.0 0.0 foo Main src/Main.hs:(8,1)-(10,24) 98 1 0.0 0.0 0.0 0.0 foo.fooSub Main src/Main.hs:10:5-24 99 1 0.0 0.0 0.0 0.0 bar Main src/Main.hs:(13,1)-(17,46) 100 1 0.0 0.0 0.0 0.0 bar.barSub Main src/Main.hs:(15,5)-(17,46) 101 1 0.0 0.0 0.0 0.0 bar.barSub.barSubSub Main src/Main.hs:17:9-46 102 1 0.0 0.0 0.0 0.0 main Main src/Main.hs:(4,1)-(5,15) 95 0 0.0 20.5 0.0 20.5
I.e., there is profiling information for all definitions, including local definitions in where
clauses.
If you only want to profile top-level definitions, you can build with the GHC option -fprof-auto-top
instead: doing stack build --profile --ghc-options=-fprof-auto-top && stack exec -- test +RTS -p
produces a ./test.prof
which includes
individual inherited COST CENTRE MODULE SRC no. entries %time %alloc %time %alloc [... many lines omitted ...] main Main src/Main.hs:(4,1)-(5,15) 97 0 0.0 0.0 0.0 0.0 foo Main src/Main.hs:(8,1)-(10,24) 98 1 0.0 0.0 0.0 0.0 bar Main src/Main.hs:(13,1)-(17,46) 99 1 0.0 0.0 0.0 0.0 main Main src/Main.hs:(4,1)-(5,15) 95 0 0.0 20.5 0.0 20.5
instead.
Finally, note that stack build --profile
also turns on stack traces. If you change the program so that barSubSub x = error $ show x
, then running stack build --profile && stack exec test
produces
test: 4 CallStack (from HasCallStack): error, called at src/Main.hs:17:23 in main:Main CallStack (from -prof): Main.bar.barSub.barSubSub (src/Main.hs:17:9-36) Main.bar.barSub (src/Main.hs:(15,5)-(17,36)) Main.bar (src/Main.hs:(13,1)-(17,36)) Main.foo.fooSub (src/Main.hs:10:5-24) Main.foo (src/Main.hs:(8,1)-(10,24)) Main.main (src/Main.hs:(4,1)-(5,15)) Main.CAF:lvl8_r4Fc (<no location info>)
Pretty cool!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With