2

このコードは、4 つの合計を計算するコードを高速化していません。その代わり、さらに時間がかかります。また、出力は期待どおりではありません。

#include <stdio.h>
#include <omp.h>
int main()
{
    int i,j,k,l;
    int sum = 0,sum1 = 0,sum2 = 0,sum3 = 0;
    #pragma omp parallel
    {
        #pragma omp sections
        {
            #pragma omp section
            {
                printf("%d",omp_get_thread_num());
                for(i = 0; i < 500000000; i++) sum = sum + 1;
            }
            #pragma omp section
            {
                printf("%d",omp_get_thread_num());
                for(i = 0; i < 500000000; i++) sum1 = sum1 + 1;
            }
            #pragma omp section
            {
                printf("%d",omp_get_thread_num());
                for(i = 0; i < 500000000; i++) sum2 = sum2 + 1;
            }
            #pragma omp section
            {
                printf("%d",omp_get_thread_num());
                for(i = 0; i < 500000000; i++) sum3 = sum3 + 1;
            }
        }
    }
    printf("sum is %d %d %d %d",    sum,sum1,sum2,sum3);
}

出力はsum is 218748707 222052401 239009041 196849489

ここでopenmpを使用する際の欠陥を教えてください。

4

2 に答える 2

5

sum速度低下は、 、sum1sum2およびsum3が共有変数であるため、シリアル バージョンの場合のように中間和をレジスタに保持するだけでなく、コンパイラがインクリメントごとにフェッチ / 更新 / ストア命令を生成する必要があることに起因します。

各合計は、それが使用されているスレッドに対してローカルにする必要があります。これを行う最も簡単な方法は、各合計を削減することです。

#pragma omp parallel private(i) reduction(+:sum,sum1,sum2,sum3)
{
    // Rest of the code goes unchanged
}

private(i)間違った結果で問題を解決します。は、各スレッドに、、およびreduction(+:sum,sum1,sum2,sum3)の独自のコピーを蓄積させ、最終的にローカル コピーを加算して最終的な値を形成します。sumsum1sum2sum3

パフォーマンスの数値を次に示します。

シリアル版 - 3.812 秒:

$ gcc -o mp.x mp.c -lgomp
$ time ./mp.x
0000sum is 500000000 500000000 500000000 500000000
./mp.x  3.81s user 0.00s system 99% cpu 3.812 total

共有変数を使用した OpenMP バージョン - 7.982 秒:

$ gcc -fopenmp -o mp.x mp.c
$ time OMP_NUM_THREADS=4 ./mp.x
0132sum is 500000000 500000000 500000000 500000000
OMP_NUM_THREADS=4 ./mp.x  21.88s user 0.86s system 284% cpu 7.982 total

削減された OpenMP バージョン - 1.226 秒:

$ gcc -fopenmp -o mp.x mp.c
$ time OMP_NUM_THREADS=4 ./mp.x
0321sum is 500000000 500000000 500000000 500000000
OMP_NUM_THREADS=4 ./mp.x  4.53s user 0.00s system 370% cpu 1.226 total

さらに速度を低下させる別のコード変換もあり、セクション コードが OpenMP プロセッサによって抽出され、別の関数に配置されている間にsum、 、sum1sum2およびsum3がメイン プログラムのスタックに置かれているという事実があります。並列チームの各スレッド。この関数には、4 つの共有合計へのポインターを含むデータ構造が提供され、コードはそれらのポインターで動作します。両方のケースでアセンブラーの出力を比較して、自分の目で確かめることができます。並列パフォーマンスについて深く掘り下げたい場合は、比較することは非常に有益です。

于 2012-06-18T08:41:21.943 に答える
3

並行性を常に自由に使用できるとは限りません。たとえば、新しいスレッドの作成、メモリ領域のロックなど、目に見えないオーバーヘッドが関係している可能性があります。些細なタスクのパフォーマンス向上を常に期待できるとは限りません。

期待どおりの出力が得られない理由は、すべてのスレッドが同じループ変数 ( i) を使用しているためです。これによりデータ競合が発生します。これが、合計が 500000000 にならない理由でもあります。

于 2012-06-18T06:20:43.473 に答える