1

私はビルディングブロックをスレッド化し、TBBでFFTアルゴリズムをエンコードして経験を積もうとするのは初めてです。このアルゴリズムの場合、最も内側のループのみを並列化できます。しかし、そうすることで、パフォーマンスが許容できない程度 (1,000 倍以上) まで低下しました。2^20 までの配列サイズを試してみましたが、同じ結果です。私のコードは以下のとおりです

for(stage1=0;stage1 < lim;stage1 ++)
{
    butterfly_index1 = butterfly_index2;
    butterfly_index2 = butterfly_index2 + butterfly_index2; 
    k = -1*2*PI/butterfly_index2;
    k_next = 0.0;
    for(stage2 = 0 ; stage2 < butterfly_index1;stage2++)
    {
        sine=sin(k_next);
        cosine = cos(k_next);
        k_next = k_next + k;
        FFT. sine = &sine;
        FFT.cosine = &cosine;
        FFT.n2 = &butterfly_index2;
        FFT.loop_init = &stage2;
        FFT.n1 = &butterfly_index1;
        parallel_for(blocked_range<int>(
                        stage2,SIZE,SIZE/4),FFT,simple_partitioner()); 
    }
}   

そして、parallel_loop の本体は

void operator()(const blocked_range<int> &r)const
{
    for(int k = r.begin(); k != r.end(); k++)
    {   
        if(k != *loop_init)
        {
            if((k - (*loop_init))% (* n2)!= 0)
                continue;
        }           
        temp_real = (*cosine) * X[k + *n1].real - (*sine) * X[k + *n1].img;
        temp_img = (*sine)* X[k + *n1].real + (*cosine) * X[k + *n1].img;
        X[k + *n1].real = X[k].real - temp_real;
        X[k + *n1].img = X[k].img - temp_img;
        X[k].real = X[k].real + temp_real;
        X[k].img = X[k].img + temp_img; 
    }
}

通常のループに置き換えると、問題はなくなります。

4

2 に答える 2

1

ワークロードが非常に短い場合、スレッド作成のオーバーヘッドが原因で、大幅な速度低下が発生する可能性があります。配列内の 2^20 要素の場合、このような大幅なパフォーマンスの低下は発生しないと思います。

パフォーマンス低下のもう 1 つの重要な原因は、TBBfied 後のコードをコンパイラが最適化 (特にベクトル化) できないことです。コンパイラーがベクトル化レポートを生成するかどうかを確認し、シリアル バージョンと TBB バージョンの違いを探します。

ボディが大量にコピーされるため、スローダウンの原因として、parallel_for のボディ クラスのコピー コンストラクターが考えられます。しかし、与えられたコードはこの点で疑わしくはありません: 本体にはいくつかのポインターが含まれているようです。とにかく、それが問題になる可能性があるかどうかを見てください。


かなりのオーバーヘッドのもう 1 つの一般的な原因は、並列処理が細かすぎることです。つまり、それぞれの作業がほとんど含まれていない多数のタスクです。しかし、ここでもそうではありません。blocked_range の 3 番目のパラメーターのgrainsize SIZE/4 は、ボディの operator()() がアルゴリズムごとに最大 4 回呼び出されることを指定しているためです。

最初の実験では simple_partitioner とgrainsize を指定せず、代わりに TBB に作業を動的に分散させることをお勧めします。必要に応じて後で調整できます。

于 2011-04-03T09:36:34.403 に答える
0

私のコードの問題は、n2変数の増加に伴うワークロードの減少でした。そのため、outループが進むにつれて、parallel_forのワークロードは半分になり、数回の反復の後、TBBを使用してパフォーマンスを向上させるには小さすぎます。したがって、解決策は、内部ループのワークロードが十分である場合に、反復に対してのみ内部ループを並列化し、残りの反復に対して内部ループをシリアル化することです。次に、条件チェック(k!= r.end())を含む「for」ループヘッダーもパフォーマンスを低下させます。解決策は、r.end()を、r.end()に初期化されたローカルで定義された変数に置き換えることです。

この問題の解決に協力してくれたIntelソフトウェアフォーラムに感謝します

于 2011-04-03T21:23:58.970 に答える