Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell GHC分析器输出_Haskell_Profiling_Ghc - Fatal编程技术网

Haskell GHC分析器输出

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

我一直在讨论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)
我使用-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,我明白了。我想剖析器不会向你展示所有这些恶棍。然而,我们可以看到他们的总成本归因于谁创造了thunks
f
快速创建
勾号
-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