如何访问和打印MPI工作人员之间分发的完整向量?

时间:2012-09-04 04:06:07

标签: c vector mpi solver ode

如何从MPI中的单个线程访问全局向量?

我正在使用一个库 - 特别是一个ODE求解器库 - 名为CVODE(SUNDIALS的一部分)。该库与MPI一起使用,因此多个线程并行运行。它们都运行相同的代码。每个线程将一个数据“旁边”发送给它。但我希望其中一个线程(rank = 0)在某些点打印出数据的状态。

library includes functions以便每个线程都可以访问自己的数据(本地向量)。但是没有方法可以访问全局向量。

我需要在特定时间输出所有方程的值。为此,我需要访问全局向量。任何人都知道如何获取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(我正在解决的函数)中,我使用MPI_SendMPI_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;
}

1 个答案:

答案 0 :(得分:4)

使用MPI时,各个线程无法访问“全局” 向量。它们不是线程,它们是可以运行的进程 不同的物理计算机,因此无法直接访问全局数据

要执行您想要的操作,您可以将矢量发送到其中一个MPI进程(您这样做)并在那里打印,或者按顺序打印本地工作器部件。使用这样的函数:

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开始。数据没有搞砸,因为只有 一个进程在任何给定时间写入。

在上面的示例中,使用了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++;
  }
}