Haskell 在repa算法函数中观察到意外性能

Haskell 在repa算法函数中观察到意外性能,haskell,repa,Haskell,Repa,我正在用以下代码测试repa-algorithms-3.2.1.1中的mmultP函数(为了简洁起见,这里有一点压缩): 以下是线程运行时中的顺序运行: $ time ./mmultTest +RTS -K100M > /dev/null real 0m10.962s user 0m10.790s sys 0m0.161s 这是一款使用4核(在4核MacBook Air上运行)的机型: 有人对这里发生的事有什么直觉吗?对于-N2和-N3,我的性能也比顺序性能慢;每个核

我正在用以下代码测试
repa-algorithms-3.2.1.1
中的
mmultP
函数(为了简洁起见,这里有一点压缩):

以下是线程运行时中的顺序运行:

$ time ./mmultTest +RTS -K100M > /dev/null
real    0m10.962s
user    0m10.790s
sys     0m0.161s
这是一款使用4核(在4核MacBook Air上运行)的机型:

有人对这里发生的事有什么直觉吗?对于
-N2
-N3
,我的性能也比顺序性能慢;每个核心似乎都增加了一些额外的时间

请注意,我确实观察到一些手工编写的Repa矩阵乘法代码的并行性带来了一些小的好处

更新

令人费解;我将
main
替换为

mmultBench :: IO ()
mmultBench  = do 
   results <- mmultP arr brr 
   let reduced = sumAllS results 
   print reduced
带有运行时选项
-N1-K100M
的标准基准测试产生:

mean: 1.361450 s, lb 1.360514 s, ub 1.362915 s, ci 0.950
std dev: 5.914850 ms, lb 3.870615 ms, ub 9.183472 ms, ci 0.950
-N4-K100M
给了我:

mean: 556.8201 ms, lb 547.5370 ms, ub 573.5012 ms, ci 0.950
std dev: 61.82764 ms, lb 40.15479 ms, ub 102.5329 ms, ci 0.950

这是一个可爱的加速。我几乎会认为前面的行为是由于将生成的1000x1000数组写入stdout,但正如我所提到的,如果我交换自己的矩阵乘法代码,我确实观察到并行性的提高。我仍在挠头。

这似乎很奇怪,但也许你只是在为并行性支付通常的费用,而没有获得好处--这类似于与荒谬的不平衡负载并联

看来肯定是出了什么问题。然而,让我震惊的是——这可能会部分解释您的结果——您只使用了一个
repa
combinator,
mmultP
。框架几乎没有机会!如果我用
zipWith
foldAllP
等的字眼使事情复杂化——例如

1) 将矩阵打印到标准输出将使程序IO绑定。在这种情况下记录的任何加速数据都是谎言


2) 没有4核MacBook Air。它们都是2个核心,每个核心有2个超线程。一次只能运行两个线程。>-N2的任何加速都将是由于延迟隐藏造成的——核心上的第二个超线程可以运行,而第一个超线程在缓存未命中时暂停。

使用3个核心时会得到什么?同样比sequential慢,但比
-N4
快。对于
-N2
,情况也一样。是的,我也从你的代码中得到了很好的加速。在更新这个问题时,我几乎愚弄了自己,因为我用
sumAllP
等做了一些并行的缩减,很好地改善了我在
-N4
下的时间;似乎我真的没有在
mmultP
上获得预期的利用率。使用我的示例中的simple
main=mmultP arr brr>>=print
是否会得到类似的时间?是的,我的结果与原始模块的结果类似。但我制作的main越复杂,我的结果就越好,至少就并行化而言。谢谢,这是我的怀疑。在手动滚动代码中进行交换导致总体性能低于
mmultP
,但在
-N2
-N4
下,交换速度确实比w/
-N1
稍快。这就是我困惑的根源。
mmultBench :: IO ()
mmultBench  = do 
   results <- mmultP arr brr 
   let reduced = sumAllS results 
   print reduced
(arr, brr) = head &&& last $ map (fromListUnboxed (Z :. 1000 :. 1000 :: DIM2)) (replicate 2 [1..1000000])
mean: 1.361450 s, lb 1.360514 s, ub 1.362915 s, ci 0.950
std dev: 5.914850 ms, lb 3.870615 ms, ub 9.183472 ms, ci 0.950
mean: 556.8201 ms, lb 547.5370 ms, ub 573.5012 ms, ci 0.950
std dev: 61.82764 ms, lb 40.15479 ms, ub 102.5329 ms, ci 0.950
main :: IO ()
main =  arr `xxx` brr >>= foldAllP (+) 0 >>= print where
   xxx arr brr = R.zipWith (+) <$> complicated arr <*> complicated brr
   complicated = mmultP brr >=> mmultP arr >=> mmultP brr >=> mmultP arr
 $ time ./mmmult +RTS -K200M  -N2
 6.2713897715510016e16

 real   0m8.742s
 user   0m16.176s
 sys    0m0.444s

 $ time ./mmmult +RTS -K200M  
 6.2713897715512584e16

 real   0m15.214s
 user   0m14.970s
 sys    0m0.239s