Profiling builds with Stack

后端 未结 4 1395
囚心锁ツ
囚心锁ツ 2020-12-22 19:51

How do I tell stack to build my executable and all its dependencies with -prof?

Simply adding it to ghc-options in the

相关标签:
4条回答
  • 2020-12-22 20:31

    Assuming a project called project-name, this is how I get a time and heap profile (with colors):

    1. Add dependencies to the build-depends section of project-name.cabal
    2. Get dependent packages: stack build
    3. From inside project-name/app compile the program with profiling enabled: stack ghc -- -prof -fprof-auto -rtsopts -O2 Main.hs
    4. Then create the heap and time profile ./Main +RTS -hc -p. This will produce Main.hp and Main.prof
    5. Turn the heap profile into a PostScript file and then into a PDF chart with colors: stack exec -- hp2ps -c Main.hp && ps2pdf Main.ps

    That's the heap profile from the PDF:

    0 讨论(0)
  • 2020-12-22 20:33

    For stack build, stack bench and stack test you can just use stack build/bench/test --profile. You may have to stack clean first to get it to recompile with profiling.

    For stack build you will still have to pass +RTS -p or whatever option you need (see GHC User Guide) when running the executable as in @Tomáš Janoušek answer.

    You can also find more information in the debugging section of the stack user guide.

    0 讨论(0)
  • 2020-12-22 20:36

    I had this problem as well and found that the problem was in the invocation:

    stack exec my-exe +RTS -p passes -p to stack instead of my-exe. This works:

    stack exec -- my-exe +RTS -p
    
    0 讨论(0)
  • 2020-12-22 20:39

    Profiling builds with Stack 1.0.0 and newer

    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.

    Avoiding unnecessary rebuilding of local packages (fixed in Stack 2.X?)

    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.

    Profiling builds with Stack versions before 1.0.0 (i.e. from 2015)

    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>
    

    Example for Stack 1.0.0 and newer

    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!

    0 讨论(0)
提交回复
热议问题