1

OpenMPのforループの並列化の方法を模倣するMPIのラッパーを実装することを考えています。

  begin_parallel_region( chunk_size=100 , num_proc=10 );

  for( int i=0 ; i<1000 ; i++ )
  {
       //some computation 
  }

  end_parallel_region();

上記のコードは、forループ内の計算を10個のスレーブMPIプロセッサに分散します。並列領域に入ると、チャンクサイズとスレーブプロセッサの数が提供されます。並列領域を離れると、MPIプロセッサは同期され、アイドル状態になります。

ハイパフォーマンスマークに応じて編集。

OpenMPの共有メモリモデルをシミュレートするつもりはありません。必要なので提案します。数学関数からグラフを作成するために必要なライブラリを開発しています。これらの数学関数には、以下のようなforループが存在することがよくあります。

 for( int i=0 ; i<n ; i++ )
 {
          s = s + sin(x[i]);
 }

したがって、最初にsin(x [i])をスレーブプロセッサに配布し、最後にOpenMPの場合と同じように単一の変数に削減できるようにしたいと思います。

車輪の再発明をする必要がないように、そのようなラッパーがそこにあるのだろうかと思っていました。

ありがとう。

4

3 に答える 3

6

研究所から逃げ出して広く使用されているようなラッパーはありません。あなたが提案しているのは、車輪を再発明することではなく、空飛ぶ車を発明することです。

ループの負担を共有する OpenMP のアプローチをシミュレートする MPI コードを作成する方法を提案する方法がわかりますが、MPI に OpenMP の共有メモリ モデルをシミュレートする方法を提案する方法はあまり明確ではありません。

単純な OpenMP プログラムでは、お勧めのように、10 個のスレッドがそれぞれ大きなループの反復の 10% を実行し、おそらく大きな (共有) データ構造の値を更新することがあります。MPI の狡猾なラッパー内でそれをシミュレートするには、(i) 片面通信が共有メモリのように動作するように説得する (これは実行可能かもしれませんが、確かに難しいでしょう) か、(ii) すべてのプロセスにデータを配布する必要があります。各プロセスに結果の 10% を個別に計算させてから、実行の最後に各プロセスが他のプロセスが持っているすべてのデータを取得できるように、結果をすべてブロードキャストします。

分散メモリ ハードウェア上で共有メモリ コンピューティングをシミュレートすることは、これまでも、これからも、並列コンピューティングのホットなトピックです。Google で分散共有メモリ コンピューティングを検索して、一緒に楽しみましょう。

編集

プロセス全体に分散している場合はx、個々のプロセスが計算sin(x[i])でき、 を使用して合計を 1 つのプロセスに減らすことができますMPI_Reduce

MPI が既に提供しているものの上に上部構造を構築する理由がわからないため、要件について何かが欠けているに違いありません。それにもかかわらず、あなたの最初の質問に対する私の答えはいいえのままです。あなたが求めるようなラッパーはありません。私の答えの残りの部分はすべて単なる解説です。

于 2012-08-27T15:47:57.233 に答える
4

はい、特定のタスクのためにこれを行うことができます。しかし、あなたはすべきではありません。

これをどのように実装するかを検討してください。開始部分はデータを配布し、終了部分は答えを返します。

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <mpi.h>

typedef struct state_t {
    int globaln;
    int localn;
    int *locals;
    int *offsets;
    double *localin;
    double *localout;
    double (*map)(double);
} state;

state *begin_parallel_mapandsum(double *in, int n, double (*map)(double)) {
    state *s = malloc(sizeof(state));
    s->globaln = n;
    s->map = map;

    /* figure out decomposition */

    int size, rank;
    MPI_Comm_size(MPI_COMM_WORLD, &size);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);

    s->locals  = malloc(size * sizeof(int));
    s->offsets = malloc(size * sizeof(int));

    s->offsets[0] = 0;

    for (int i=0; i<size; i++) {
        s->locals[i] = (n+i)/size;
        if (i < size-1) s->offsets[i+1] = s->offsets[i] + s->locals[i];
    }

    /* allocate local arrays */
    s->localn   = s->locals[rank];
    s->localin  = malloc(s->localn*sizeof(double));
    s->localout = malloc(s->localn*sizeof(double));


    /* distribute */
    MPI_Scatterv( in, s->locals, s->offsets, MPI_DOUBLE,
                  s->localin, s->locals[rank], MPI_DOUBLE,
                  0, MPI_COMM_WORLD);

    return s;
}

double  end_parallel_mapandsum(state **s) {
    double localanswer=0., answer;

    /* sum up local answers */
    for (int i=0; i<((*s)->localn); i++) {
        localanswer += ((*s)->localout)[i];
    }

    /* and get global result.  Everyone gets answer */
    MPI_Allreduce(&localanswer, &answer, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);

    free( (*s)->localin );
    free( (*s)->localout );
    free( (*s)->locals );
    free( (*s)->offsets );
    free( (*s) );

    return answer;
}


int main(int argc, char **argv) {
    int rank;
    double *inputs;
    double result;
    int n=100;
    const double pi=4.*atan(1.);

    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);

    if (rank == 0) {
        inputs = malloc(n * sizeof(double));
        for (int i=0; i<n; i++) {
            inputs[i] = 2.*pi/n*i;
        }
    }

    state *s=begin_parallel_mapandsum(inputs, n, sin);

    for (int i=0; i<s->localn; i++) {
        s->localout[i] = (s->map)(s->localin[i]);
    }

    result = end_parallel_mapandsum(&s);

    if (rank == 0) {
        printf("Calculated result: %lf\n", result);
        double trueresult = 0.;
        for (int i=0; i<n; i++) trueresult += sin(inputs[i]);
        printf("True  result: %lf\n", trueresult);
    }

    MPI_Finalize();

}

この絶え間ない分散/収集は、いくつかの数値を合計すると通信の負担が大きく、分散メモリ コンピューティング モデル全体とは対照的です。

最初の概算では、共有メモリ アプローチ (OpenMP、pthreads、IPP など) は、計算を高速にスケーリングすることに関するものです。メモリの同じチャンクでより多くのプロセッサを投入することについて。一方、分散メモリ コンピューティングとは、計算をより大きくスケーリングすることです。単一のコンピュータで見られるよりも多くのリソース、特にメモリを使用することについて。MPI を使用する大きな利点は、どのノードのメモリにも収まらない問題セットを扱う場合です。そのため、分散メモリ コンピューティングを行う場合、すべてのデータを 1 つの場所に保持することは避けます。

MPI オンノードを使用してすべてのプロセッサを使用する場合でも、この基本的なアプローチを念頭に置いておくことが重要です。上記のスキャッター/ギャザー アプローチは、パフォーマンスを低下させるだけです。より慣用的な分散メモリ コンピューティングのアプローチは、プログラムのロジックが既にデータを分散しているというものです。つまり、ループの最初の段階でbegin_parallel_regionend_parallel_region以上のコードが既にループ上のコードに組み込まれています。次に、すべてのループは

 for( int i=0 ; i<localn ; i++ )
    {
          s = s + sin(x[i]);
    }

タスク間でデータを交換する必要がある場合 (または結果を減らす場合など) は、MPI 関数を呼び出してそれらの特定のタスクを実行します。

于 2012-08-28T14:20:34.297 に答える
1

MPI は必須ですか、それともクラスターで OpenMP のようなコードを実行しようとしているだけですか? 後者の場合は、Intel の Cluster OpenMP を参照することをお勧めします。

http://www.hpcwire.com/hpcwire/2006-05-19/openmp_on_clusters-1.html

于 2012-08-27T15:34:38.913 に答える