我正在通过使用-prof
进行编译在Haskell程序中寻找优化机会,但是我不知道如何解释包含椭圆的成本中心。什么是filter.(...)
和jankRoulette.select.(...)
?
COST CENTRE MODULE %time %alloc
filter.(...) Forest 46.5 22.3
set-union Forest 22.5 4.1
cache-lookup Forest 16.0 0.1
removeMany MultiMapSet 3.7 1.9
insertMany MultiMapSet 3.3 1.8
jankRoulette.select.(...) Forest 1.4 15.2
我生成的是:
$ ghc --make -rtsopts -prof -auto-all main.hs && ./main +RTS -p && cat main.prof
函数
filter
在where
子句中有一些定义,如下所示:filter a b = blahblah where
foo = bar
bar = baz
baz = bing
但是这些都显示为
filter.foo
,filter.bar
等。我以为它们可能是嵌套的let表达式,但是
jankRoulette.select
没有任何表达式。而且,我在大多数指令之前添加了SCC指令,而没有任何成本中心升至最高。由于大部分时间都用在
filter.(...)
中,所以我想知道那是什么。 :) 最佳答案
TL; DR:当您在let绑定(bind)中进行模式匹配时,GHC会生成此代码,例如let (x,y) = c
。 c
成本中心会跟踪评估...
的成本(因为它没有唯一的名称)。
那么我是怎么发现的呢?
GHC源代码中(...)
的grep可以找到以下内容(来自editor/deSugar/Coverage.hs):
-- TODO: Revisit this
addTickLHsBind (L pos (pat@(PatBind { pat_lhs = lhs, pat_rhs = rhs }))) = do
let name = "(...)"
(fvs, rhs') <- getFreeVars $ addPathEntry name $ addTickGRHSs False False rhs
{- ... more code following, but not relevant to this purpose
-}
该代码告诉我们,它必须对模式绑定(bind)进行某些操作。
因此,我们可以制作一个小的测试程序来检查行为:
x :: Int
(x:_) = reverse [1..1000000000]
main :: IO ()
main = print x
然后,我们可以在启用概要分析的情况下运行该程序。实际上,GHC产生以下输出:
COST CENTRE MODULE no. entries %time %alloc %time
%alloc
MAIN MAIN 42 0 0.0 0.0 100.0 100.0
CAF Main 83 0 0.0 0.0 100.0 100.0
(...) Main 86 1 100.0 100.0 100.0 100.0
x Main 85 1 0.0 0.0 0.0 0.0
main Main 84 1 0.0 0.0 0.0 0.0
因此,事实证明,从代码中得出的假设是正确的。该程序的所有时间都用于评估
reverse [1..1000000000]
表达式,并将其分配给(...)
成本中心。