使用 Stack 分析构建
Profiling builds with Stack
如何告诉 stack
使用 -prof
构建我的可执行文件及其所有依赖项?
仅仅将它添加到 .cabal
文件中的 ghc-options
是不够的,因为它只尝试构建启用分析的可执行文件,但失败了。
使用 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>
对于 <profiling options>
,您可能需要 -p
进行时间分析或 -h
进行内存分析。对于时间分析,分析显示在 ./<your program>.prof
中,对于内存分析,分析显示在 ./<your program>.hp
.
中
有关更多分析选项,请参阅 GHC profiling documentation。
避免不必要的本地包重建(已在 Stack 2.X 中修复?)
由于 长期存在的堆栈
问题,
在分析和非分析构建之间切换可能会导致很多
不必要的本地包重建和 extra-deps
。上班
围绕这一点,您可以使用单独的构建缓存进行分析和
非分析构建。例如,您将 stack <cmd>
用于
您可以使用非分析
stack --work-dir .stack-work-profile --profile <cmd>
用于 <cmd>
的分析版本。这使用一个单独的
在 .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>
Stack 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 && 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>)
很酷!
我也遇到了这个问题,发现问题出在调用上:
stack exec my-exe +RTS -p
将 -p
传递给堆栈而不是 my-exe。这有效:
stack exec -- my-exe +RTS -p
对于 stack build
、stack bench
和 stack test
,您可以只使用 stack build/bench/test --profile
。您可能必须先 stack clean
才能使用分析重新编译它。
对于 stack build
,您仍然需要通过 +RTS -p
或您需要的任何选项(参见 GHC User Guide) when running the executable as in 。
您还可以在 debugging section of the stack user guide 中找到更多信息。
假设一个名为 project-name
的项目,这就是我获取时间和堆配置文件(带有颜色)的方式:
- 将依赖项添加到
project-name.cabal
的 build-depends
部分
- 获取依赖包:
stack build
- 从内部
project-name/app
用profiling enabled编译程序:stack ghc -- -prof -fprof-auto -rtsopts -O2 Main.hs
- 然后创建 heap and time 配置文件
./Main +RTS -hc -p
。这将产生 Main.hp
和 Main.prof
- 将堆配置文件转换为 PostScript file,然后转换为具有以下颜色的 PDF 图表:
stack exec -- hp2ps -c Main.hp && ps2pdf Main.ps
这是 PDF 中的堆配置文件:
如何告诉 stack
使用 -prof
构建我的可执行文件及其所有依赖项?
仅仅将它添加到 .cabal
文件中的 ghc-options
是不够的,因为它只尝试构建启用分析的可执行文件,但失败了。
使用 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>
对于 <profiling options>
,您可能需要 -p
进行时间分析或 -h
进行内存分析。对于时间分析,分析显示在 ./<your program>.prof
中,对于内存分析,分析显示在 ./<your program>.hp
.
有关更多分析选项,请参阅 GHC profiling documentation。
避免不必要的本地包重建(已在 Stack 2.X 中修复?)
由于 长期存在的堆栈
问题,
在分析和非分析构建之间切换可能会导致很多
不必要的本地包重建和 extra-deps
。上班
围绕这一点,您可以使用单独的构建缓存进行分析和
非分析构建。例如,您将 stack <cmd>
用于
您可以使用非分析
stack --work-dir .stack-work-profile --profile <cmd>
用于 <cmd>
的分析版本。这使用一个单独的
在 .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>
Stack 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 && 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>)
很酷!
我也遇到了这个问题,发现问题出在调用上:
stack exec my-exe +RTS -p
将 -p
传递给堆栈而不是 my-exe。这有效:
stack exec -- my-exe +RTS -p
对于 stack build
、stack bench
和 stack test
,您可以只使用 stack build/bench/test --profile
。您可能必须先 stack clean
才能使用分析重新编译它。
对于 stack build
,您仍然需要通过 +RTS -p
或您需要的任何选项(参见 GHC User Guide) when running the executable as in
您还可以在 debugging section of the stack user guide 中找到更多信息。
假设一个名为 project-name
的项目,这就是我获取时间和堆配置文件(带有颜色)的方式:
- 将依赖项添加到
project-name.cabal
的 - 获取依赖包:
stack build
- 从内部
project-name/app
用profiling enabled编译程序:stack ghc -- -prof -fprof-auto -rtsopts -O2 Main.hs
- 然后创建 heap and time 配置文件
./Main +RTS -hc -p
。这将产生Main.hp
和Main.prof
- 将堆配置文件转换为 PostScript file,然后转换为具有以下颜色的 PDF 图表:
stack exec -- hp2ps -c Main.hp && ps2pdf Main.ps
build-depends
部分
这是 PDF 中的堆配置文件: