答案 0 :(得分:64)
代码审核备注
rsize
未使用(看起来很贵!)(**)
的所有用途都可以由(^)
上更便宜的Int
替换。any (==True)
与or
时间分析
COST CENTRE MODULE %time %alloc
squared_diff Main 25.0 27.3
insideParticle Main 13.8 15.3
sum_squared_diff Main 9.8 5.6
rcoords Main 7.4 5.6
particle_extended Main 6.8 9.0
particle_slice Main 5.0 7.6
insideParticles Main 5.0 4.4
yslice Main 3.6 3.0
xslice Main 3.0 3.0
ssd_vec Main 2.8 2.1
**^ Main 2.6 1.4
表明,您的函数squared_diff
有点可疑:
squared_diff :: Array DIM2 Double
squared_diff = deepSeqArrays [rcoords,particle_extended]
((force2 rcoords) -^ (force2 particle_extended)) **^ 2
虽然我没有看到任何明显的修复。
空间分析
在空间配置文件中没有太多惊人的东西:你清楚地看到列表阶段,然后是矢量阶段。列表阶段分配了一大部分,然后回收。
按类型分解堆,我们最初看到很多列表和元组被分配(按需),然后分配并保存了一大块数组:
再一次,有点像我们期望看到的......数组内容的分配特别不是列表代码(实际上总体上要少一些),但运行起来只需要更长的时间。
使用保留器分析检查空间泄漏:
那里有一些有趣的东西,但没什么好吃的。 zcoords
保留列表程序执行的长度,然后为修复运行分配一些数组(SYSTEM)。
检查核心
所以在这一点上我首先假设你确实在列表和数组中实现了相同的算法(即在数组的情况下没有进行额外的工作),并且没有明显的空间泄漏。所以我怀疑是非常优化的修复代码。让我们看看核心(ghc-core。
内联所有CAF
我为所有顶级数组定义添加了内联编译指示,希望删除一些CAFS,并让GHC更难以优化数组代码。这确实使GHC难以编译模块(在处理模块时分配高达4.3G和10分钟)。这对我来说是一个线索,GHC以前不能很好地优化这个程序,因为当我增加阈值时,它会有新的东西。
操作强>
答案 1 :(得分:7)
我将代码更改为强制rcoords
和particle_extended
,并且发现我们在其中直接失去了大部分时间:
COST CENTRE MODULE %time %alloc
rcoords Main 32.6 34.4
particle_extended Main 21.5 27.2
**^ Main 9.8 12.7
对此代码的最大改进显然是以更好的方式生成这两个常量输入。
请注意,这基本上是一个懒惰的流式算法,而你失去时间的是一次性分配至少两个24361803元素数组的沉没成本,然后可能至少分配一次或两次或者放弃分享。我认为,对于这个代码来说,最好的情况是使用非常好的优化器和大量的重写规则,将大致匹配列表版本(也可以非常容易地并行化)。
我认为Ben和amp;合。我会对这个基准测试感兴趣,但我绝对怀疑这对于一个严格的数组库来说不是一个好的用例,而我怀疑matlab隐藏了一些聪明的优化它的ngrid
函数(优化,我' ll grant,这可能对移植到port有用。)
修改强>
这是一种快速而又脏的方法来并行化列表代码。导入Control.Parallel.Strategies
,然后将numberInsideParticles
写为:
numberInsideParticles particles coords = length $ filter id $
withStrategy (parListChunk 2000 rseq) $ P.map (insideParticles particles) coords
这显示了良好的加速,因为我们扩展核心(一个核心12s到8s时3.7s),但火花创建的开销意味着即使是8个核心,我们也只匹配单核心非并行版本。我尝试了一些替代策略并得到了类似的结果。同样,我不确定我们可以做多少比这里的单线程列表版本更好。由于每个粒子的计算都很便宜,我们主要强调的是分配,而不是计算。我想象的这样一个大赢家将是矢量化计算,而且据我所知,它几乎需要手工编码。
另请注意,并行版本大约70%的时间花在GC上,而单核版本花费1%的时间在那里(即分配尽可能地被有效地融合掉)。
答案 2 :(得分:7)
我已经添加了一些关于如何优化Haskell wiki的Repa程序的建议: http://www.haskell.org/haskellwiki/Numeric_Haskell:_A_Repa_Tutorial#Optimising_Repa_programs