使用 Stack 分析构建

Posted

技术标签:

【中文标题】使用 Stack 分析构建【英文标题】:Profiling builds with Stack 【发布时间】:2015-08-20 16:24:22 【问题描述】:

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

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

【问题讨论】:

【参考方案1】:

使用 Stack 1.0.0 和更高版本分析构建

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

stack build --profile

您可能需要先运行stack clean,然后再运行this should be fixed in Stack 1.5.0。

个人资料:

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

&lt;profiling options&gt; 的位置可能需要 -p 进行时间分析或 -h 进行内存分析。对于时间分析,配置文件出现在./&lt;your program&gt;.prof,对于内存分析,配置文件出现在./&lt;your program&gt;.hp

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

避免不必要地重建本地包(在 Stack 2.X 中修复?)

由于long standing Stack issue, 在分析和非分析构建之间切换可能会导致很多 不必要地重建本地包和extra-deps。去工作 围绕这一点,您可以使用单独的构建缓存进行分析和 非分析构建。例如,您使用 stack &lt;cmd&gt; 表示 您可以使用的非配置文件

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

对于&lt;cmd&gt; 的分析版本。这使用了一个单独的 缓存在.stack-work-profile 中用于分析工件, 而默认情况下将保留非分析工件 .stack-work缓存。

使用 1.0.0 之前的 Stack 版本(即从 2015 年开始)分析构建

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

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

个人资料:

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

堆栈 1.0.0 及更高版本的示例

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

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 &amp;&amp; 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 &amp;&amp; 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 &amp;&amp; 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>)

很酷!

【讨论】:

这不起作用。使用 stack exec my-exe +RTS -p 显示可执行文件尚未使用 -prof 编译,尝试这样做表明 ld 找不到库的配置文件版本。 这对我有用:stack install --enable-executable-profiling --enable-library-profiling --ghc-options="-fprof-auto -rtsopts" @ChrisStryczynski:我刚刚编辑了我的答案。希望对您有所帮助。 你能把.stack-work-profile的部分放在第一位吗?我第一次阅读这个答案时,我看到了第一行并做到了,然后我读下去就后悔了。 您好,从 2019 年开始!今天使用 Stack 2.1.3,这些说明对我不起作用。我还需要将--profile 添加到stack exec 调用中。这有效:stack build --profile &amp;&amp; stack exec --profile -- my-exe +RTS ...【参考方案2】:

我也遇到了这个问题,发现问题出在调用中:

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

stack exec -- my-exe +RTS -p

【讨论】:

【参考方案3】:

对于stack buildstack benchstack test,您可以使用stack build/bench/test --profile。您可能需要先stack clean 才能通过分析重新编译它。

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

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

【讨论】:

您也可以在堆栈构建命令的末尾添加“--force-dirty”来强制它重新编译。 你的意思是说stack exec【参考方案4】:

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

    将依赖项添加到project-name.cabalbuild-depends 部分 获取依赖包:stack buildproject-name/app内部用profiling enabled编译程序:stack ghc -- -prof -fprof-auto -rtsopts -O2 Main.hs 然后创建heap 和time 配置文件./Main +RTS -hc -p。这将产生Main.hpMain.prof 将堆配置文件转换为PostScript file,然后转换为带有颜色的PDF图表:stack exec -- hp2ps -c Main.hp &amp;&amp; ps2pdf Main.ps

这是 PDF 中的堆配置文件:

【讨论】:

@LupusOssorum:我不知道是否有办法将.prof 文件转换为 PDF。但是有.prof文件的可视化工具,例如profiteur、professor和viewprof。

以上是关于使用 Stack 分析构建的主要内容,如果未能解决你的问题,请参考以下文章

C++ 不使用虚析构的后果及分析

集中式日志分析平台 Elastic Stack(介绍)

集中式日志分析平台 Elastic Stack(介绍)

ES 集中式日志分析平台 Elastic Stack(介绍)

stack(STL)

3析构函数分析