使用Stack构建分析

问题描述 投票:48回答:4

如何告诉stack使用-prof构建我的可执行文件及其所有依赖项?

简单地将它添加到ghc-options文件中的.cabal是不够的,因为它只会尝试构建启用了性能分析的可执行文件,但这会失败。

haskell cabal haskell-stack
4个回答
75
投票

Profiling builds with Stack 1.0.0 and newer

要在启用分析的情况下构建:

stack build --profile

您可能需要首先运行stack clean,但this should be fixed in Stack 1.5.0

要简介:

stack exec -- <your program> +RTS <profiling options>

在哪里为<profiling options>你可能想要-p进行时间分析或-h进行内存分析。对于时间分析,配置文件显示在./<your program>.prof中,对于内存分析,配置文件显示在./<your program>.hp中。

有关更多性能分析选项,请参阅GHC profiling documentation

Avoiding unnecessary rebuilding of local packages

由于long standing Stack issue,在分析和非分析构建之间切换会导致大量不必要的重建本地包和extra-deps。要解决此问题,您可以为分析和非分析构建使用单独的构建缓存。例如,您可以使用stack <cmd>进行非分析

stack --work-dir .stack-work-profile --profile <cmd>

对于<cmd>的分析版本。这在.stack-work-profile中使用单独的缓存来分析工件,而非分析工件将保留在默认的.stack-work缓存中。

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

要在启用分析的情况下构建:

stack build --executable-profiling --library-profiling --ghc-options="-fprof-auto -rtsopts"

要简介:

stack exec -- <your program> +RTS <profiling options>

Example for Stack 1.0.0 and newer

假设您有一个名为test的包,其中包含test定义的单个可执行文件main

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

然后做stack build --profile && stack exec -- test +RTS -p将产生一个文件./test.prof,其中包括

                                                                                                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

即,所有定义都有分析信息,包括where子句中的局部定义。

如果你只想描述顶级定义,你可以使用GHC选项-fprof-auto-top来构建:做stack build --profile --ghc-options=-fprof-auto-top && stack exec -- test +RTS -p产生一个./test.prof,其中包括

                                                                                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

代替。

最后,请注意stack build --profile也会打开堆栈跟踪。如果你改变程序使barSubSub x = error $ show x,然后运行stack build --profile && stack exec test产生

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>)

太酷了!


14
投票

我也有这个问题,发现问题出在调用中:

stack exec my-exe +RTS -p将-p传递给堆栈而不是my-exe。这有效:

stack exec -- my-exe +RTS -p

4
投票

对于stack buildstack benchstack test你可以使用stack build/bench/test --profile。您可能必须首先使stack clean通过分析重新编译它。

对于stack build,在+RTS -p中运行可执行文件时,您仍然需要传递GHC User Guide或任何您需要的选项(请参阅@Tomáš Janoušek answer)。

您还可以在debugging section of the stack user guide中找到更多信息。


1
投票

假设一个名为project-name的项目,这就是我获取时间和堆配置文件(带颜色)的方法:

  1. 将依赖项添加到build-dependsproject-name.cabal部分
  2. 获得依赖包:stack build
  3. project-name/app里面用profiling enabled编译程序:stack ghc -- -prof -fprof-auto -rtsopts -O2 Main.hs
  4. 然后创建heaptime配置文件./Main +RTS -hc -p。这将产生Main.hpMain.prof
  5. 将堆配置文件转换为PostScript file,然后转换为带有颜色的PDF图表:stack exec -- hp2ps -c Main.hp && ps2pdf Main.ps

这是PDF的堆配置文件:

heap_profile_with_colors

© www.soinside.com 2019 - 2024. All rights reserved.