2012-11-25 5 views
6

Haskellプログラムでマルチスレッド機能を追加しようとしたところ、パフォーマンスが改善しないことに気付きました。それを追うと、スレッドスコープから次のデータが得られます。Haskellプログラムでのマルチスレッドパフォーマンスのプロファイリング - 並列ストラテジを使用したスピードアップなし

Graph 1 緑色は実行中、オレンジ色はガベージコレクションです。 Graph 2 Graph 3 ここで、緑色のバーはスパークの作成を示し、青色のバーは並列のGCリクエストを示し、薄い青色のバーはスレッドの作成を示します。 Graph 4 ラベルである:スレッドを作成、並列GCを要求し、作成したスパークnは、平均してキャップから2

をスパークを盗む、私だけでは改善されなかった、4つのコア上に、約25%の活性を取得していシングルスレッドプログラム全体で

もちろん、実際のプログラムの説明がなくても問題は解決されません。基本的には、トラバース可能なデータ構造(ツリーなど)を作成し、その上に関数をfmapしてから、イメージ書き込みルーチンに渡します(15秒を過ぎたプログラム実行の最後に明白にシングルスレッドのセグメントを説明します) 。関数の構築とfmappingの両方が実行にかなりの時間を要しますが、第2の関数はそれほど多くありません。

上記のグラフは、イメージの書き込みによって消費される前に、そのデータ構造に対してparTraversable戦略を追加することによって作成されました。また、データ構造をtoListにして、さまざまなパラレルリストストラテジ(parList、parListChunk、parBuffer)を使用してみましたが、結果は大規模なチャンクを使用してもさまざまなパラメータに似ていました。
また、関数をfmappingする前にtraversableデータ構造を完全に評価しようとしましたが、まったく同じ問題が発生しました。ここで

は、(同じプログラムの異なる実行のための)いくつかの追加の統計です:

5,702,829,756 bytes allocated in the heap 
    385,998,024 bytes copied during GC 
     55,819,120 bytes maximum residency (8 sample(s)) 
     1,392,044 bytes maximum slop 
      133 MB total memory in use (0 MB lost due to fragmentation) 

            Tot time (elapsed) Avg pause Max pause 
    Gen 0  10379 colls, 10378 par 5.20s 1.40s  0.0001s 0.0327s 
    Gen 1   8 colls,  8 par 1.01s 0.25s  0.0319s 0.0509s 

    Parallel GC work balance: 1.24 (96361163/77659897, ideal 4) 

         MUT time (elapsed)  GC time (elapsed) 
    Task 0 (worker) : 0.00s (15.92s)  0.02s ( 0.02s) 
    Task 1 (worker) : 0.27s (14.00s)  1.86s ( 1.94s) 
    Task 2 (bound) : 14.24s (14.30s)  1.61s ( 1.64s) 
    Task 3 (worker) : 0.00s (15.94s)  0.00s ( 0.00s) 
    Task 4 (worker) : 0.25s (14.00s)  1.66s ( 1.93s) 
    Task 5 (worker) : 0.27s (14.09s)  1.69s ( 1.84s) 

    SPARKS: 595854 (595854 converted, 0 overflowed, 0 dud, 0 GC'd, 0 fizzled) 

    INIT time 0.00s ( 0.00s elapsed) 
    MUT  time 15.67s (14.28s elapsed) 
    GC  time 6.22s ( 1.66s elapsed) 
    EXIT time 0.00s ( 0.00s elapsed) 
    Total time 21.89s (15.94s elapsed) 

    Alloc rate 363,769,460 bytes per MUT second 

    Productivity 71.6% of total user, 98.4% of total elapsed 

私は答える支援するために与えることができる有用な他のどのような情報がわかりません。プロファイリングは面白いことは明らかにしていません。これは、単一のコア統計と同じですが、IDLEが上記の時間の75%を占めることを除いては、上記のとおりです。

有用な並列化が行われないのはどういうことですか?

+0

あなたはどこか、コード、またはコードの少なくとも関連部分を持っていますか? – shachaf

+0

私はプログラムから関連するコードを抽出すると、上に概説した説明がすべて正確に残っているので、実際のコードを含めると役立たないことがわかりました。 また、私がfmapを使っている関数が、それが純粋である限り重要であることは私には分かりません。それはたとえ横断可能な構造の構築がそうでなくても、何に関係なく並列化可能でなければならない。 – Will

+0

小さなレポを作成します。おそらく、あなたはそれを自分自身で行うことができます。もしそうでなければ、我々はレポを見ることができる。 – usr

答えて

4

申し訳ありませんが、回答者を支援するためのコードを適時に提供できませんでした。問題の正確な位置を解くのにはしばらく時間がかかりました。私はトラバースデータ構造上

f :: a -> S b 

S及びTは、2つのトラバースファンクタである

structure :: T a 

の機能をfmappingた次のよう

問題がありました。

parTraversableを使用するときに、私は誤って私は間違ってData.Functorを使用(マルチスレッド化を行うために作曲TSためTraversableのインスタンスを使用していた

Compose (fmap f structure) `using` parTraversable rdeepseq 

代わりの

Compose $ fmap f structure `using` parTraversable rdeepseq 

を書いていました.Compose)。

(キャッチしやすいしてきたはずですようにこれが見えますが、それはコードから上記の間違いを抽出するために、私はしばらく時間がかかった!)

これは今、非常に良く見えます!

Graph 1

Graph 2

関連する問題