在每个进程上收集不同长度的数组

时间:2017-06-22 10:54:39

标签: arrays mpi

我有np个进程和np个不同长度的不同数组。我必须将其中一个发送到每个进程(对所有进程重复相同)。其中一个np部分应保留在该流程上。

在3个流程的情况下应该是:

  

p0[A0 B0 C0],最终应该有[A0 A1 A2]

     

p1[A1 B1 C1],最终应该有[B0 B1 B2]

     

p2[A2 B2 C2],最终应该有[C0 C1 C2]

我的想法是首先收集所有长度,然后分配内存,最后执行MPI_gatherv操作,同时更改根等级,如共享信息:

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

int main(int argc, char **argv) {

  MPI_Init(&argc, &argv); 

  int rank, size;
  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
  MPI_Comm_size(MPI_COMM_WORLD, &size);
  if(size!=3){
    MPI_Finalize();
    printf("execution with np = 3 only\n");
    return 1;
  }

  int a[5],b[5],c[5],len_a,len_b,len_c;

  if(rank == 0){ 
     a[0] = 0 ; 
     b[0] = 30; 
     c[0] = 60; 
     len_a = len_b = len_c = 1;
     //a,b,c can have different lengths 
  }
  else if(rank == 1){
     a[0] = 1 ; a[1] = 11; 
     b[0] = 31; b[1] = 41; 
     c[0] = 61; c[1] = 71; 
     len_a = len_b = len_c = 2;
     //a,b,c can have different lengths 
  }
  else if(rank == 2){
     a[0] = 2 ; a[1] = 12; a[2] = 22;
     b[0] = 32; b[1] = 42; b[2] = 52;
     c[0] = 62; c[1] = 72; c[2] = 82;
     len_a = len_b = len_c = 3;
     //a,b,c can have different lengths 
  }

  /*

  At the end I should have

  rank 0 : a = { 0  | 1  11  | 2  12 22 }
  rank 1 : b = { 30 | 31 41  | 32 42 52 }
  rank 2 : c = { 60 | 61 71  | 62 72 82 }

  */

  int lengths[3];
  int tot_length;

  /*
   * we Gather the lengths for every process as root 
   */

  int mylen,i,root = 0;

  for(i=0;i<3;i++){
    root = i;

    mylen = rank + 1;

    MPI_Gather(&mylen, 
           1, 
           MPI_INT,
               lengths, 
           1,
               MPI_INT,
               root,
               MPI_COMM_WORLD);

  }

  /*
     calculate tot_length of my elem array 
     and determine the disp vector
  */

  int displs[3];
  displs[0] = 0;
  tot_length = lengths[0];

  for(i=1;i<3;i++){
    displs[i] = displs[i-1] + lengths[i-1];
    tot_length += lengths[i];
  }

  printf("rank %d lengths = %d %d %d displs = %d %d %d \n", rank, \
      lengths[0],lengths[1],lengths[2],                           \
      displs[0],displs[1],displs[2]);

  int *elem = malloc(tot_length * sizeof(int));
  int  myvec[5];
  int  j;

  for(i=0;i<3;i++){

    root = i;
    if(root == 0){
      for(j=0;j<5;j++)
        myvec[j]=a[j];
    }
    else if(root == 1){
      for(j=0;j<5;j++)
        myvec[j]=b[j];
    }
    else if(root == 2){
      for(j=0;j<5;j++)
        myvec[j]=c[j];
    }

    MPI_Gatherv(myvec,
                mylen,
                MPI_INT,
                elem,
                lengths,
                displs,
                MPI_INT,
                root,
                MPI_COMM_WORLD);

  }

  printf("rank %d elem : ",rank);
  for(i=0;i<tot_length;i++){
    printf("%d ", elem[i]);
  }
  printf("\n");


  MPI_Finalize();
  return 0;
}

有没有更好的方法或有效的内置功能来执行此操作?

1 个答案:

答案 0 :(得分:2)

首先,您可以使用MPI_Allgather代替MPI_Gather循环来分配长度。

然后,您描述的操作是MPI_Alltoall操作:

illustration of All_gather / Alltoall

但是,使用不同变量的数据会使事情变得复杂。你可以使用一些MPI_Bottom /类型的voodoo,但我宁愿建议将不同等级的数据放在一个连续的数组中 - 然后使用MPI_Alltoallv来分发它。