2011-07-06 32 views
2

我必須使用MPI_Allgather()將結構發送到所有進程。我似乎沒有得到任何明顯的錯誤,但代碼不起作用。當我檢查我是否收到recv[]中的任何值時,它不顯示任何值。如果我只是發送一個變量而不是使用類似代碼的結構,那麼它就可以工作,所以我不確定發生了什麼。該結構有靜態數組,所以內存應該是連續的,或者我應該使用MPI_Pack什麼的?這裏是代碼:使用MPI_Allgather分配結構

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

#define NUMEL 21 
struct mystruct{ 
int sendarray[10]; 
int a; 
char array2[10]; 
}; 

typedef struct mystruct struct_t; 

int main (int argc, char ** argv) 
{ 
MPI_Status status; 
int rank, size; 
char *recv; 
int i, j; 
MPI_Init(&argc, &argv); 
MPI_Comm_rank(MPI_COMM_WORLD, &rank); 
MPI_Comm_size(MPI_COMM_WORLD, &size); 
// init 
struct_t * fd = (struct_t*)malloc(sizeof(*fd));; 
for (i=0;i<10;i++){ 
    fd->sendarray[i] = 0; 
    fd->array2[i] = 0; 
} 
recv = (char *) malloc (size*NUMEL); 

// put some stuff in your array 
for (i=0;i<size;i++){ 
    if(rank == i){ 
     fd->sendarray[i] = i *10; 
     fd->array2[i] = i *20; 
     fd->a = rank; 
    } 
    if(fd->sendarray[i] != 0) 
    printf("My rank is %d, fd->sendarray[%d] is %d\n", rank, i, fd->sendarray[i]); 
    } 

    // gather data from all now.. 
    MPI_Allgather (fd, NUMEL, MPI_BYTE, recv, NUMEL * size, MPI_INT, MPI_COMM_WORLD); 

    // check if correct data has been received 
    for (i=0;i<size*NUMEL;i++){ 
    if(recv[i] != 0) 
    printf("My rank is %d and recv[i]=%d and i is %d\n", rank, recv[i],i); 
    } 
MPI_Finalize(); 
} 

回答

9

Allgather第一次看到它可能有點困惑。這裏有一些事情要做。

一是allgather計數 - 發送計數和recv的數 - 是每個進程發送數據量,並從每個過程收到

其次,allgather的工作方式是連接發送的數據。所以,如果你有

int send[3]; 
int recv[9]; 

隨着對每個進程發送陣列看起來像這樣:

send: 
     +---+---+---+ 
     | 0 | 0 | 0 |  rank 0 
     +---+---+---+ 

     +---+---+---+ 
     | 1 | 1 | 1 |  rank 1 
     +---+---+---+ 

     +---+---+---+ 
     | 2 | 2 | 2 |  rank 2 
     +---+---+---+ 

然後調用

MPI_Allgather(send, 3, MPI_INT, recv, 3, MPI_INT, MPI_COMM_WORLD); 

會導致:

recv: 
     +---+---+---+---+---+---+---+---+---+ 
     | 0 | 0 | 0 | 1 | 1 | 1 | 2 | 2 | 2 |  
     +---+---+---+---+---+---+---+---+---+ 

所以你的代碼版本是哪個拉出正確的數據是:

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

struct mystruct{ 
    int sendarray[10]; 
    int a; 
    char array2[10]; 
}; 

typedef struct mystruct struct_t; 

int main (int argc, char ** argv) 
{ 
    int rank, size; 
    struct_t *recv; 
    int i, j; 
    MPI_Init(&argc, &argv); 
    MPI_Comm_rank(MPI_COMM_WORLD, &rank); 
    MPI_Comm_size(MPI_COMM_WORLD, &size); 
    // init 
    struct_t * fd = (struct_t*)malloc(sizeof(*fd)); 
    for (i=0;i<10;i++){ 
     fd->sendarray[i] = 0; 
     fd->array2[i] = 0; 
    } 
    recv = malloc (size * sizeof(*fd)); 

    // put some stuff in your array 
    fd->sendarray[rank] = rank*10; 
    fd->array2[rank] = rank*20; 
    fd->a = rank; 
    printf("My rank is %d, fd->sendarray[%d] is %d\n", rank, i, fd->sendarray[i]); 

    // gather data from all now.. 
    MPI_Allgather (fd, sizeof(*fd), MPI_BYTE, recv, sizeof(*fd), MPI_BYTE, MPI_COMM_WORLD); 


    // check if correct data has been received 
    if (rank == 0) { 
     printf("Received:\n"); 
     for (i=0;i<size;i++){ 
      printf("---\n"); 
      printf("int array: "); 
      for (j=0; j<10; j++) printf("%3d ", recv[i].sendarray[j]); 
      printf("\nint:  "); printf("%3d\n", recv[i].a); 
      printf("char array: "); 
      for (j=0; j<10; j++) printf("%3d ", (int)(recv[i].array2[j])); 
      printf("\n"); 
     } 
    } 
    MPI_Finalize(); 
    return 0; 
} 

請注意,它將這些結構收集到相當於這些結構的數組中。有4個處理器運行得:

My rank is 0, fd->sendarray[10] is 0 
My rank is 1, fd->sendarray[10] is 1 
My rank is 2, fd->sendarray[10] is 2 
My rank is 3, fd->sendarray[10] is 3 

Received: 
--- 
int array: 0 0 0 0 0 0 0 0 0 0 
int:   0 
char array: 0 0 0 0 0 0 0 0 0 0 
--- 
int array: 0 10 0 0 0 0 0 0 0 0 
int:   1 
char array: 0 20 0 0 0 0 0 0 0 0 
--- 
int array: 0 0 20 0 0 0 0 0 0 0 
int:   2 
char array: 0 0 40 0 0 0 0 0 0 0 
--- 
int array: 0 0 0 30 0 0 0 0 0 0 
int:   3 
char array: 0 0 0 60 0 0 0 0 0 0 

如果你真的想只是相應的元素聚集,那麼你會簡單地從特定位置發送一個INT /炭的結構:

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

struct mystruct{ 
    int sendarray[10]; 
    int a; 
    char array2[10]; 
}; 

typedef struct mystruct struct_t; 

int main (int argc, char ** argv) 
{ 
    int rank, size; 
    struct_t fd; 
    struct_t recv; 
    int i, j; 
    MPI_Init(&argc, &argv); 
    MPI_Comm_rank(MPI_COMM_WORLD, &rank); 
    MPI_Comm_size(MPI_COMM_WORLD, &size); 
    // init 
    for (i=0;i<10;i++){ 
     fd.sendarray[i] = 0; 
     fd.array2[i] = 0; 

     recv.sendarray[i] =999; 
     recv.array2[i] = 99; 
    } 
    recv.a =999; 

    // put some stuff in your array 
    fd.sendarray[rank] = rank*10; 
    fd.array2[rank] = (char)(rank*20); 
    fd.a = rank; 
    printf("My rank is %d, fd.sendarray[%d] is %d\n", rank, rank, fd.sendarray[rank]); 

    // gather data from all now.. send the int: 
    MPI_Allgather (&(fd.sendarray[rank]), 1, MPI_INT, recv.sendarray, 1, MPI_INT, MPI_COMM_WORLD); 
    // then the char 
    MPI_Allgather (&(fd.array2[rank]), 1, MPI_CHAR, recv.array2, 1, MPI_CHAR, MPI_COMM_WORLD); 

    // check if correct data has been received 
    if (rank == 0) { 
     printf("Received:\n"); 
     printf("---\n"); 
     printf("int array: "); 
     for (j=0; j<10; j++) printf("%3d ", recv.sendarray[j]); 
     printf("\nint:  "); printf("%3d\n", recv.a); 
     printf("char array: "); 
     for (j=0; j<10; j++) printf("%3d ", (int)(recv.array2[j])); 
     printf("\n"); 
    } 
    MPI_Finalize(); 

    return 0; 
} 

如果我們運行4個進程,我們得到:

My rank is 0, fd.sendarray[0] is 0 
My rank is 1, fd.sendarray[1] is 10 
My rank is 2, fd.sendarray[2] is 20 
My rank is 3, fd.sendarray[3] is 30 
Received: 
--- 
int array: 0 10 20 30 999 999 999 999 999 999 
int:  999 
char array: 0 20 40 60 99 99 99 99 99 99 
+2

謝謝!這非常有幫助! – lostinpointers