1

元のコードは次のようになります

for(i=0;i<20;i++){
    if(){
        do(); 
    }
    else{

        num2 = _mm_set_pd(Phasor.imaginary, Phasor.real);

        for(int k=0; k<SamplesIneachPeriodCeil[iterationIndex]; k++) 
        {
            /*SamplesIneachPeriodCeil[iterationIndex] is in range of 175000*/

            num1 = _mm_loaddup_pd(&OutSymbol[k].real);
            num3 = _mm_mul_pd(num2, num1);
            num1 = _mm_loaddup_pd(&OutSymbol[k].imaginary);
            num2 = _mm_shuffle_pd(num2, num2, 1);
            num4 = _mm_mul_pd(num2, num1);
            num3 = _mm_addsub_pd(num3, num4);
            num2 = _mm_shuffle_pd(num2, num2, 1);
            num5 = _mm_set_pd(InSymbolInt8[k],InSymbolInt8[k] );
            num6 = _mm_mul_pd(num3, num5);
            num7 = _mm_set_pd(Out[k].imaginary,Out[k].real);
            num8 = _mm_add_pd(num7,num6);
            _mm_storeu_pd((double *)&Out[k], num8);

        }
        Out = Out + SamplesIneachPeriodCeil[iterationIndex];
    }
}

このコードは私にard15milsecの速度を与えます

openmpを含むようにコードを変更したとき

注::ここでは、else部分のみを含めています

else{
    int size = SamplesIneachPeriodCeil[iterationIndex];

#pragma omp parallel num_threads(2) shared(size)
    {
        int start,end,tindex,tno,no_of_iteration;
        tindex = omp_get_thread_num();
        tno = omp_get_num_threads();
        start = tindex * size / tno;
        end = (1+ tindex)* size / tno ;
        num2 = _mm_set_pd(Phasor.imaginary, Phasor.real);
        int k;
        for(k = start ; k < end; k++){


            num1 = _mm_loaddup_pd(&OutSymbol[k].real);
            num3 = _mm_mul_pd(num2, num1);
            num1 = _mm_loaddup_pd(&OutSymbol[k].imaginary);
            num2 = _mm_shuffle_pd(num2, num2, 1);
            num4 = _mm_mul_pd(num2, num1);
            num3 = _mm_addsub_pd(num3, num4);
            //_mm_storeu_pd((double *)&newSymbol, num3);
            num2 = _mm_shuffle_pd(num2, num2, 1);
            num5 = _mm_set_pd(InSymbolInt8[k],InSymbolInt8[k] );
            num6 = _mm_mul_pd(num3, num5);
            num7 = _mm_set_pd(Out[k].imaginary,Out[k].real);
            num8 = _mm_add_pd(num7,num6);
            _mm_storeu_pd((double *)&Out[k], num8);


        }
    }
    Out = Out + size;
}

このコードが示す速度はどこか30ミル秒です

だから私はここで何か間違ったことをしたのだろうかと思っていました。

4

2 に答える 2

2

2 つのスレッド間でループの実行を分散するために何もしていません。2 つのスレッドで並列領域を作成しているだけで、それらのスレッドはまったく同じコードを実行します。やりたいことは、並列領域を移動してforループのみを取り囲み、ワークシェアリング構造を使用することです。

int k;
#pragma omp parallel for num_threads(2) ...
for(k = start ; k < end; k++){
   ...
}

修正してくれたTudorに感謝します。コードは正しく並列化されていますが、ループ内に並列領域があります。並列領域への出入りには、いくらかのオーバーヘッドが伴います。通常、これは「フォーク/ジョイン モデル」と呼ばれます。このモデルでは、リージョンに入るときにスレッドのチームが作成され、終了するときにすべてのスレッドがマスターに結合されます。ほとんどの OpenMP ランタイムは、さまざまなスレッド プーリング手法を使用してオーバーヘッドを削減していますが、それでもオーバーヘッドは存在します。

ループは 15 ミリ秒間実行されます。これは、OpenMP のオーバーヘッドと比較してすでに十分に高速であるため、オーバーヘッドが目に見えるようになります。並列領域を外側のループに移動すると、オーバーヘッドは最大 20 分の 1 に減少するはずですが (else分岐の発生頻度によって異なります)、それでも計算時間の改善は見られない可能性があります。

並列化は、問題が十分に大きく、通信または同期のオーバーヘッドが計算時間と比較して無視できるか、少なくとも小さいプログラムにのみ適用できます。

于 2012-05-24T07:53:16.727 に答える
0

外側のループの外で並列領域を開始し ( を介してi)、 for ループをkを使用して並列化する必要がありますomp for。ループ内で使用されるすべての変数 ( num1num2...) は、自動的に宣言されるように、それらの中でのみ宣言するのが最適ですprivate(実際には、それらのほとんどは再利用できますが、コンパイラーはとにかくそれを見つける必要があります)。

于 2012-05-28T11:53:32.127 に答える