7

OpenMPを使って簡単なアプリケーションを書いてみます。残念ながら、スピードアップに問題があります。このアプリケーションでは、whileループが1つあります。このループの本体は、順次実行する必要のあるいくつかの命令と1つのforループで構成されています。私は#pragma omp parallel forこれをforループを並列にするために使用します。このループはあまり機能しませんが、頻繁に呼び出されます。

forループの2つのバージョンを準備し、1、2、および4コアでアプリケーションを実行します。
バージョン1(forループで4回の反復):22秒、23秒、26秒。
バージョン2(forループで100000回の反復):20秒、10秒、6秒。

ご覧のとおり、forループの作業が少ない場合、2コアと4コアの方が1コアよりも時間がかかります。#pragma omp parallel forその理由は、whileループの反復ごとに新しいスレッドが作成されるためだと思います。だから、私はあなたに尋ねたいと思います-一度(whileループの前に)スレッドを作成し、whileループのいくつかのジョブが順番に実行されることを保証する可能性はありますか?

#include <omp.h>
#include <iostream>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
int main(int argc, char* argv[])
{
    double sum = 0;
    while (true)
    {
        // ...
        // some work which should be done sequentially
        // ...

        #pragma omp parallel for num_threads(atoi(argv[1])) reduction(+:sum)
        for(int j=0; j<4; ++j)  // version 2: for(int j=0; j<100000; ++j)
        {
            double x = pow(j, 3.0);
            x = sqrt(x);
            x = sin(x);
            x = cos(x);
            x = tan(x);
            sum += x;

            double y = pow(j, 3.0);
            y = sqrt(y);
            y = sin(y);
            y = cos(y);
            y = tan(y);
            sum += y;

            double z = pow(j, 3.0);
            z = sqrt(z);
            z = sin(z);
            z = cos(z);
            z = tan(z);
            sum += z;
        }

        if (sum > 100000000)
        {
            break;
        }
    }
    return 0;
}
4

2 に答える 2

10

ほとんどのOpenMP実装は、プログラムの起動時に多数のスレッドを作成し、プログラムの期間中それらを保持します。つまり、ほとんどの実装は、実行中にスレッドを動的に作成および破棄しません。そうすることは、深刻なスレッド管理コストでパフォーマンスに打撃を与えるでしょう。スレッド管理へのこのアプローチは、OpenMPの通常のユースケースと一致しており、適切です。

OpenMPスレッドの数を増やしたときに見られる速度低下は、反復回数が少ないループに並列オーバーヘッドを課すことに起因する可能性がはるかに高くなります。フリストの答えはこれをカバーしています。

于 2012-05-15T08:09:40.633 に答える
5

while (true)並列領域をループの外側に移動し、singleディレクティブを使用して、コードのシリアル部分を1つのスレッドでのみ実行するようにすることができます。これにより、フォーク/結合モデルのオーバーヘッドが削除されます。また、OpenMPは、反復回数が非常に少ない(バージョン1のように)thightループではあまり役に立ちません。ループ内の作業は非常に高速に行われるため、基本的にOpenMPのオーバーヘッドを測定しています。超越関数を使用した100000回の反復でも、現世代のCPUでは1秒未満で完了します(2 GHzで、追加以外のFP機器あたり約100サイクル)。約100ミリ秒かかります)。

そのため、OpenMPは、if(condition)小さなループの並列化を選択的にオフにするために使用できる句を提供します。

#omp parallel for ... if(loopcnt > 10000)
for (i = 0; i < loopcnt; i++)
   ...

またschedule(static)、通常のループ(つまり、すべての反復の計算にほぼ同じ時間がかかるループ)に使用することをお勧めします。

于 2012-05-14T20:49:23.560 に答える