3

mmultP私は次のコードで関数をテストしていましたrepa-algorithms-3.2.1.1(簡潔にするためにここに少し要約します):

import Data.Array.Repa hiding            (map)
import Data.Array.Repa.Algorithms.Matrix (mmultP)

import Control.Monad                     (replicateM)
import Control.Arrow                     ((&&&))
import System.Random.MWC                 (initialize, uniformR)
import Control.Monad.ST                  (runST)
import Data.Vector.Unboxed               (singleton)
import Data.Word                         (Word32)

-- Create a couple of dense matrices
genRnds :: Word32 -> [Double]
genRnds seed = runST $ do
    gen <- initialize (singleton seed)
    replicateM (1000 ^ 2) (uniformR (0, 1) gen)

(arr, brr) = head &&& last $ map (fromListUnboxed (Z :. 1000 :. 1000 :: DIM2) . genRnds) [1, 100000]

-- mmultP test
main :: IO ()
main = mmultP arr brr >>= print

ここで指定されているように、

ghc mmultTest.hs -Odph -rtsopts -threaded -fno-liberate-case -funfolding-use-threshold1000 -funfolding-keeness-factor1000 -fllvm -optlo-O3 -fforce-recomp

スレッドランタイムでの順次実行は次のとおりです。

$ time ./mmultTest +RTS -K100M > /dev/null
real    0m10.962s
user    0m10.790s
sys     0m0.161s

これが4コアを使用したものです(4コアMacBook Airで実行):

$ time ./mmultTest +RTS -N4 -K100M > /dev/null
real    0m13.008s
user    0m18.591s
sys     0m2.067s

ここで何が起こっているのか、誰か直感がありますか?-N2また、とのパフォーマンスが順次より遅くなり-N3ます。各コアは、さらに時間を追加するようです。

手巻きのRepa行列乗算コードでは、並列処理によるわずかな向上が見られることに注意してください

更新

不可解; に置き換えmainました

mmultBench :: IO ()
mmultBench  = do 
   results <- mmultP arr brr 
   let reduced = sumAllS results 
   print reduced

との依存関係を削除しましたmwc-random

(arr, brr) = head &&& last $ map (fromListUnboxed (Z :. 1000 :. 1000 :: DIM2)) (replicate 2 [1..1000000])

ランタイムオプションを使用したCriterionベンチマークでは、次の-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に書き込んだことによるものだとほぼ思いますが、前述したように、独自の行列乗算コードを交換すると、並列処理の向上が見られます。まだ頭をかいて。

4

2 に答える 2

2

これは奇妙に思えますが、並列処理の通常の支払いを行っているだけで、メリットを享受していないのではないでしょうか。-それで、それは不条理に不均衡な負荷で並列化することに似ていますか?

もっと何かが間違っているに違いないようです。しかし、私を驚かせたのは、結果の部分的な説明になるかもしれませんが、使用しているrepaコンビネータは1つだけであるということですmmultP。フレームワークにはほとんどチャンスがありません!zipWith散水などで問題を複雑にした場合foldAllP-例:

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

次に、2コアのジャロピーを使用して、2コアのパラレルライザーの夢を実現します。

 $ 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
于 2012-08-02T17:11:37.877 に答える
1

1)行列をstdoutに出力すると、プログラムのIOバウンドが作成されます。この状況で記録されたスピードアップの数字はすべて嘘になります。

2)4コアのMacBookAirはありません。それらはすべて2コアであり、コアごとに2つのハイパースレッドがあります。実際に一度に実行できるスレッドは2つだけです。> -N2での高速化は、レイテンシーの非表示によるものです。コア上の2番目のハイパースレッドは、最初のハイパースレッドがキャッシュミスで停止している間に実行できます。

于 2012-08-06T03:46:44.437 に答える