0

MPI で個々のスレッドからグローバル ベクトルにアクセスするにはどうすればよいですか?

CVODE ( SUNDIALSの一部) と呼ばれるライブラリ、具体的には ODE ソルバー ライブラリを使用しています。ライブラリは MPI で動作するため、複数のスレッドが並行して実行されます。それらはすべて同じコードを実行しています。各スレッドは、「隣の」スレッドにデータを送信します。しかし、スレッドの 1 つ (ランク = 0) が、ある時点でデータの状態を出力するようにします。

ライブラリには、各スレッドが独自のデータ (ローカル ベクトル) にアクセスできるようにする関数が含まれていますしかし、グローバルベクトルにアクセスする方法はありません。

特定の時間にすべての方程式の値を出力する必要があります。そのためには、グローバル ベクトルにアクセスする必要があります。MPI ベクトル内のすべてのデータを取得する方法を知っている人はいますか (可能であれば CVODE を使用)。

たとえば、各スレッドが実行する私のコードは次のとおりです

  for (iout=1, tout=T1; iout <= NOUT; iout++, tout += DTOUT) {
    flag = CVode(cvode_mem, tout, u, &t, CV_NORMAL);
    if(check_flag(&flag, "CVode", 1, my_pe)) break;
    if (my_pe == 0) PrintData(t, u);
  }
...
static void PrintData(realtype t, N_Vector u) {
   I want to print data from all threads in here
}

関数f(私が解いている関数) では、 and を使用してデータをやり取りしMPI_SendますMPI_Recv。しかし、他のプロセスが先に実行されているため、PrintData で実際にそれを行うことはできません。また、メッセージングのオーバーヘッドを追加したくありません。のグローバル ベクトルにアクセスして、PrintData必要なものを出力したいだけです。出来ますか?

編集:より良い答えを待っている間、データを0番目のスレッドに戻す各スレッドをプログラムしました。メッセージングのオーバーヘッドが増えすぎているとは思いませんが、より良い方法があれば、専門家の意見を聞きたいです (悪い方法はないと確信しています! :D )。

編集 2 : angainor のソリューションは確かに優れていますが、私が作成したものに固執しました。同じ質問をした人の将来の参考のために、ここに私がそれをした方法の基本があります:

/* Is called by all threads */
static void PrintData(realtype t, N_Vector u, UserData data) {

... declarations and such ...

  for (n=1; n<=my_length; n++) {
    mass_num = my_base + n;
    z[mass_num - 1] = udata[n-1];
    z[mass_num - 1 + N] = udata[n - 1 + my_length];
  }

  if (my_pe != 0) {
    MPI_Send(&z, 2*N, PVEC_REAL_MPI_TYPE, 0, my_pe, comm);

  } else {

    for (i=1; i<npes; i++) {
      MPI_Recv(&z1, 2*N, PVEC_REAL_MPI_TYPE, i, i, comm, &status);
      for (n=0; n<2*N; n++)
        z[n] = z[n] + z1[n];
    }

... now I can print it out however I like...

  return;
}
4

1 に答える 1

4

MPI を使用する場合、個々のスレッドは「グローバル」ベクトルにアクセスできません。それらはスレッドではなく、異なる物理コンピューターで実行できるプロセスであるため、グローバル データに直接アクセスすることはできません。

必要なことを行うには、ベクトルを MPI プロセスの 1 つに送信して (実行した)、そこで印刷するか、ローカル ワーカー パーツを順番に印刷します。次のような関数を使用します。

void MPI_write_ivector(int thrid, int nthr, int vec_dim, int *v)
{
  int i, j;
  int curthr = 0;

  MPI_Barrier(MPI_COMM_WORLD);
  while(curthr!=nthr){
    if(curthr==thrid){
      printf("thread %i writing\n", thrid);
      for(i=0; i<vec_dim; i++) printf("%d\n", v[i]);
      fflush(stdout);
      curthr++;
      MPI_Bcast(&curthr, 1, MPI_INT, thrid, MPI_COMM_WORLD);
    } else {
      MPI_Bcast(&curthr, 1, MPI_INT, curthr, MPI_COMM_WORLD);
    }
  }
}

内部にバリアとブロードキャストがあるため、すべての MPI プロセスは同時に呼び出す必要があります。基本的に、この手順では、すべての MPI プロセスがランク 0 から順番にベクトル部分を出力するようにします。常に 1 つのプロセスだけが書き込みを行うため、データが乱れることはありません。

上記の例では、スレッドが結果を出力する順序をより柔軟に指定できるため、Broadcast が使用されています。現在出力しているスレッドが次に誰を出力するかを決定できます。ブロードキャストをスキップして、バリアのみを使用することもできます

void MPI_write_ivector(int thrid, int nthr, int vec_dim, int *v)
{
  int i, j;
  int curthr = 0;

  while(curthr!=nthr){
    if(curthr==thrid){
      printf("thread %i writing\n", thrid);
      for(i=0; i<vec_dim; i++) printf("%d\n", v[i]);
      fflush(stdout);
    }
    MPI_Barrier(MPI_COMM_WORLD);
    curthr++;
  }
}
于 2012-09-04T06:55:16.573 に答える