Haskell GHC分析器输出
我一直在讨论Haskell中的空间泄漏问题,并试图理解ghc profiler提供的图形输出(在使用hp2ps之后) 具体来说,这是我正在查看的代码:Haskell GHC分析器输出,haskell,profiling,ghc,Haskell,Profiling,Ghc,我一直在讨论Haskell中的空间泄漏问题,并试图理解ghc profiler提供的图形输出(在使用hp2ps之后) 具体来说,这是我正在查看的代码: main = print (f [1..4000000] (0 :: Int, 1 :: Int)) f [] c = c f (x:xs) c = f xs (tick x c) tick x (c0,c1) | even x = (c0,c1+1) | otherwise = (c0+1,c1) 我
main = print (f [1..4000000] (0 :: Int, 1 :: Int))
f [] c = c
f (x:xs) c = f xs (tick x c)
tick x (c0,c1) | even x = (c0,c1+1)
| otherwise = (c0+1,c1)
我使用-hb标志运行程序,以对堆进行传记分析:
我不明白为什么这么多的内存被认为是无效的类别,因为这意味着大量的内存被分配给从未使用过的对象。我将producer profile限制为仅获取producer profile限制为void component的输出的无效组件:
有没有什么方法可以找出到底是什么形成的thunk导致了void的使用?使用更多(局部)变量。替换
main = print (f [1..4000000] (0 :: Int, 1 :: Int))
与
这样,您将看到一个条目main.list/main/main.CAF
,精确显示4M长的列表占用了多少空间。您可能会发现它占用了很多空间,因为它被默认为[Integer]
。将其定义为[Int]
,以改善空间
此外,f/main/..
已经显示在您自己的帖子中占据了大量空间。事实上,它类似于左非严格折叠,性能很差
让事情变得更严格,我们得到
f [] c = c
f (x:xs) c = f xs $! tick x c
tick x (c0,c1) | even x = (,) c0 $! c1+1
| otherwise = ((,) $! c0+1) c1
现在代码以恒定时间运行,即使不使用Int
如果我们使用-O2
打开优化,GHC 8.0.1也会自动执行此优化
不过,一般来说,使用显式类型注释是一个好主意,这样GHC就不会引入不需要的/不需要的多态性,并执行更好的类型检查。一般来说,这也会触发更多的优化。顺便说一下:
f
本质上是一个左折的、非严格的。这已经是“不好的”,因为它总是会分配大量的thunk,不管勾选
做什么。我会严格要求,并且会使勾选强制输出对的组件。这不是你要问的,但我看不出你是否明白发生了什么,你只是想在分析数据中得到确认(以便了解如何在将来处理更复杂的情况)。顺便说一下,我在GHC 8.0.1上用-O2编译了你的确切代码,在GHC 7.10.3上用-O2编译了它需要超过100MB,它比未经选择的版本要好得多。似乎在8.0.1中有了很大的改进。profiler已经告诉您哪些成本中心导致了分配——这是CAF。由于您不需要手动定义CAF,因此需要查看程序的核心,以查看哪些表达式已成为CAF(除非您具有非凡的洞察力和经验,并且能够准确预测编译器如何编译您的程序)。谢谢,我确实意识到,通过添加bang符号使参数变得严格将使程序在更少的空间内工作。但是我更感兴趣的是找出thunks是被创造出来的。我相信对f[1,2,3,4]的评估将经历以下几个阶段:f[2,3,4]勾选1(0,1)->f[3,4]勾选2(勾选1(0,1))->。。。滴答声4(滴答声3(滴答声2(滴答声1(0,1)))->一系列滴答声,然后计算滴答声4(滴答声3(滴答声2(0+1,1))->滴答声4(滴答声3(0+1,1))->。。。(((0+1)+1),((1+1)+1))是(+)的一系列重击。然而,我无法将这些计算阶段与图形中的点关联起来(特别是与表示对象已创建但从未使用过的void组件关联起来)@SureshSudhakaran,我明白了。我想剖析器不会向你展示所有这些恶棍。然而,我们可以看到他们的总成本归因于谁创造了thunksf
快速创建勾号
-thunk,然后通过打印
更慢地使用。在f
最终返回一对后,print
将强制第一个组件开始分配+1+1…
thunks(第一个黑色尖峰)。然后,print
对第二个组件(第二个黑色尖峰)也执行相同的操作。+1+1
的内存分配不是在评估滴答序列时就已经发生了吗?@SureshSudhakaran我也无法将-hb
绘图与执行关联起来。我不知道空白部分是这样的,我发现-hc
输出更清晰。
f [] c = c
f (x:xs) c = f xs $! tick x c
tick x (c0,c1) | even x = (,) c0 $! c1+1
| otherwise = ((,) $! c0+1) c1