2015-11-03 58 views
3

我正在學習MPI並試驗實例。MPI_Scatter和收集MPI中的二維矩陣使用C

 Fatal error in PMPI_Scatter: Invalid buffer pointer, error stack: 
    PMPI_Scatter(783): MPI_Scatter(sbuf=0x6021e0, scount=16, MPI_INT, rbuf=0x6021e0, rcount=16, MPI_INT, root=0, MPI_COMM_WORLD) failed 
    PMPI_Scatter(710): Buffers must not be aliased 

=================================================================================== 
= BAD TERMINATION OF ONE OF YOUR APPLICATION PROCESSES 
= EXIT CODE: 1 
= CLEANING UP REMAINING PROCESSES 
= YOU CAN IGNORE THE BELOW CLEANUP MESSAGES 
=================================================================================== 

我的代碼

我得到的錯誤是:

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

    #define SIZE 8   /* Size of matrices */ 
    #define MAX_RAND  100 

    int A[SIZE][SIZE], B[SIZE][1], C[SIZE][1],D[SIZE][SIZE],E[SIZE][1]; 

    void fill_matrix(int m[SIZE][SIZE]) 
    { 
    //static int n=0; 
    int i, j; 

    printf("\n*****************************\n"); 
    for (i=0; i<SIZE; i++) 
     { 
      for (j=0; j<SIZE; j++){  
       m[i][j] = rand() % MAX_RAND; 
       printf("%2d ", m[i][j]); 
      } 
     printf("\n"); 
     } 
     printf("\n*****************************\n"); 
    } 



    void fill_vector(int m[SIZE][1]) 
    { 
    //static int n=0; 
    int i, j; 

    printf("\n*****************************\n"); 
     for (i=0; i<SIZE; i++) 
     { 
      for (j=0; j<1; j++){  
       m[i][j] = rand() % MAX_RAND; 
       printf("%2d ", m[i][j]); 
      } 
     printf("\n"); 
     } 
     printf("\n*****************************\n"); 
    } 


    void print_matrix(int m[SIZE][SIZE]) 
    { 
     int i, j = 0; 
     for (i=0; i<SIZE; i++) { 
     printf("\n\t| "); 
     for (j=0; j<SIZE; j++) 
      printf("%2d ", m[i][j]); 
     printf("|"); 
     } 
    } 




    void print_vector(int m[SIZE][1]) 
    { 
     int i, j = 0; 
     for (i=0; i<SIZE; i++) { 
     printf("\n\t| "); 
     for (j=0; j<1; j++) 
      printf("%2d ", m[i][j]); 
     printf("|"); 
     } 
    } 


    int main(int argc, char *argv[]) 
    { 
     int myrank, P, from, to, i, j, k; 
    // int tag = 666;  /* any value will do */ 
    // MPI_Status status; 

     MPI_Init (&argc, &argv); 
     MPI_Comm_rank(MPI_COMM_WORLD, &myrank); /* who am i */ 
     MPI_Comm_size(MPI_COMM_WORLD, &P); /* number of processors */ 


     if (SIZE%P!=0) { 
     if (myrank==0) printf("Matrix size not divisible by number of processors\n"); 
     MPI_Finalize(); 
     exit(-1); 
     } 

     from = myrank * SIZE/P; 
     to = ((myrank+1) * SIZE/P); 

     /* Process 0 fills the input matrices and broadcasts them to the rest */ 
     /* (actually, only the relevant stripe of A is sent to each process) */ 

     if (myrank==0) { 

    { 
     //static int n=0; 
     int i, j; 

     printf("\n*****************************\n"); 
     for (i=0; i<SIZE; i++) 
     { 
      for (j=0; j<SIZE; j++){  
       A[i][j] = rand() % MAX_RAND;   
       printf("%d ", A[i][j]); 
      } 
     printf("\n"); 
     } 
     printf("\n*****************************\n"); 
    } 
     fill_vector(B); 
     } 

     int s=SIZE*SIZE/P; 
    // printf("computing slice %d (from row %d to %d)\n", myrank, from, to-1); 
     MPI_Bcast (B, SIZE*1, MPI_INT, 0, MPI_COMM_WORLD); 
    // printf("\n\n%d",s); 
     //print_vector(s); 
    //printf("\n\n"); 

     MPI_Scatter (&A, SIZE*SIZE/P, MPI_INT, &A[from], SIZE*SIZE/P, MPI_INT, 0, MPI_COMM_WORLD); 


     printf("computing slice %d (from row %d to %d)\n", myrank, from, to-1); 
     for (i=from; i<to; i++) 
     for (j=0; j<SIZE; j++) { 
      C[i][0]=0; 
      for (k=0; k<SIZE; k++){ 
      C[i][0] += A[i][k]*B[k][0]; 
     } 
     } 

     MPI_Gather (&C[from], SIZE*SIZE/P, MPI_INT, &C, SIZE*SIZE/P, MPI_INT, 0, MPI_COMM_WORLD); 

     if (myrank==0) { 
     printf("\n\n"); 

     { 
      int i, j = 0; 
       for (i=0; i<SIZE; i++) { 
         printf("\n\t| "); 
        for (j=0; j<SIZE; j++) 
         printf("%d ", A[i][j]); 
         printf("|"); 
      } 
      } 

     printf("\n\n"); 
     print_matrix(D); 
     printf("\n\n\t  * \n"); 
     print_vector(B); 
     printf("\n\n\t  = \n"); 
     print_vector(C); 
     printf("\n\n"); 
     print_vector(E); 
     printf("\n\n"); 
     } 

     MPI_Finalize(); 
     return 0; 
    } 

,因爲我java程序員,所以不是很瞭解指針,所以如果我的問題聽起來很愚蠢原諒我,我仍在學習。我在這裏要做的是將一個矩陣行分成不同的處理器,並將整個B Vector廣播出來,並將兩者相乘以得到C向量,然後再次使用收集函數接收C向量。

回答

2

兩件事情從您的代碼出現了:

  • 正如你已經猜到了,一個是與指針錯誤。 MPI_Scatter()需要指向要發送數據的指針以及指向將接收數據的緩衝區的指針。例如,由於是A的二維陣列(在存儲器中連續):

    MPI_Scatter (&A[0][0], SIZE*SIZE/P, MPI_INT, &A[from][0], SIZE*SIZE/P, MPI_INT, 0, MPI_COMM_WORLD); 
    

其中&A[0][0]是指針到發送緩衝區和&A[from][0]是指針到接收緩衝區。

  • 第二個問題在MPI_Gather()。當然,也會出現與第一個相同的錯誤。此外,C是一個向量,而不是矩陣:發送的整數數量遠低於SIZE*SIZE/P。因此,要發送的整數的數量是SIZE/P

    MPI_Gather (&C[from][0], SIZE/P, MPI_INT, &C[0][0], SIZE/P, MPI_INT, 0, MPI_COMM_WORLD); 
    

    其中int C[SIZE][1]是一個載體。

這裏是你的代碼做一些修改:

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

#define SIZE 8   /* Size of matrices */ 
#define MAX_RAND  100 

int A[SIZE][SIZE], B[SIZE][1], C[SIZE][1];//D[SIZE][SIZE],E[SIZE][1]; 

void fill_matrix(int m[SIZE][SIZE]) 
{ 
    //static int n=0; 
    int i, j; 

    printf("\n*****************************\n"); 
    for (i=0; i<SIZE; i++) 
    { 
     for (j=0; j<SIZE; j++){  
      m[i][j] = rand() % MAX_RAND; 
      printf("%2d ", m[i][j]); 
     } 
     printf("\n"); 
    } 
    printf("\n*****************************\n"); 
} 



void fill_vector(int m[SIZE][1]) 
{ 
    //static int n=0; 
    int i, j; 

    printf("\n*****************************\n"); 
    for (i=0; i<SIZE; i++) 
    { 
     for (j=0; j<1; j++){  
      m[i][j] = rand() % MAX_RAND; 
      printf("%2d ", m[i][j]); 
     } 
     printf("\n"); 
    } 
    printf("\n*****************************\n"); 
} 


void print_matrix(int m[SIZE][SIZE]) 
{ 
    int i, j = 0; 
    for (i=0; i<SIZE; i++) { 
     printf("\n\t| "); 
     for (j=0; j<SIZE; j++) 
      printf("%2d ", m[i][j]); 
     printf("|"); 
    } 
} 




void print_vector(int m[SIZE][1]) 
{ 
    int i, j = 0; 
    for (i=0; i<SIZE; i++) { 
     printf("\n\t| "); 
     for (j=0; j<1; j++) 
      printf("%2d ", m[i][j]); 
     printf("|"); 
    } 
} 


int main(int argc, char *argv[]) 
{ 
    int myrank, P, from, to, i, j, k; 
    // int tag = 666;  /* any value will do */ 
    // MPI_Status status; 

    MPI_Init (&argc, &argv); 
    MPI_Comm_rank(MPI_COMM_WORLD, &myrank); /* who am i */ 
    MPI_Comm_size(MPI_COMM_WORLD, &P); /* number of processors */ 


    if (SIZE%P!=0) { 
     if (myrank==0) printf("Matrix size not divisible by number of processors\n"); 
     MPI_Finalize(); 
     exit(-1); 
    } 

    from = myrank * SIZE/P; 
    to = ((myrank+1) * SIZE/P); 

    /* Process 0 fills the input matrices and broadcasts them to the rest */ 
    /* (actually, only the relevant stripe of A is sent to each process) */ 

    if (myrank==0) { 


     //static int n=0; 
     int i, j; 

     printf("\n*****************************\n"); 
     for (i=0; i<SIZE; i++) 
     { 
      for (j=0; j<SIZE; j++){  
       A[i][j] = rand() % MAX_RAND;   
       printf("%d ", A[i][j]); 
      } 
      printf("\n"); 

      printf("\n*****************************\n"); 
     } 
     fill_vector(B); 
    } 

    //int s=SIZE*SIZE/P; 
    // printf("computing slice %d (from row %d to %d)\n", myrank, from, to-1); 
    MPI_Bcast (B, SIZE*1, MPI_INT, 0, MPI_COMM_WORLD); 
    // printf("\n\n%d",s); 
    //print_vector(s); 
    //printf("\n\n"); 
    if(myrank==0){ 
     MPI_Scatter (&A[0][0], SIZE*SIZE/P, MPI_INT, MPI_IN_PLACE, SIZE*SIZE/P, MPI_INT, 0, MPI_COMM_WORLD); 
    }else{ 
     MPI_Scatter (&A[0][0], SIZE*SIZE/P, MPI_INT, &A[from][0], SIZE*SIZE/P, MPI_INT, 0, MPI_COMM_WORLD); 
    } 


    printf("computing slice %d (from row %d to %d)\n", myrank, from, to-1); 
    for (i=from; i<to; i++) 
     for (j=0; j<SIZE; j++) { 
      C[i][0]=0; 
      for (k=0; k<SIZE; k++){ 
       C[i][0] += A[i][k]*B[k][0]; 
      } 
     } 

    if(myrank==0){ 
     MPI_Gather (MPI_IN_PLACE, SIZE/P, MPI_INT, &C[0][0], SIZE/P, MPI_INT, 0, MPI_COMM_WORLD); 
    }else{ 
     MPI_Gather (&C[from][0], SIZE/P, MPI_INT, &C[0][0], SIZE/P, MPI_INT, 0, MPI_COMM_WORLD); 
    } 

    if (myrank==0) { 
     printf("\n\n"); 

     { 
      int i, j = 0; 
      for (i=0; i<SIZE; i++) { 
       printf("\n\t| "); 
       for (j=0; j<SIZE; j++) 
        printf("%d ", A[i][j]); 
       printf("|"); 
      } 
     } 

     printf("\n\n"); 
     // print_matrix(D); 
     printf("\n\n\t  * \n"); 
     print_vector(B); 
     printf("\n\n\t  = \n"); 
     print_vector(C); 
     printf("\n\n"); 
     // print_vector(E); 
     // printf("\n\n"); 
    } 

    MPI_Finalize(); 
    return 0; 
} 

它可以通過mpicc main.c -o main -Wall編譯和mpirun -np 4 main跑了。

我想比srand()不用於得到可重現的結果。如果你打算使用更大的數組,你將需要分配它們。如果是這樣的話,看看下面的問題:sending blocks of 2D array in C using MPI

編輯:我應該注意到,發送緩衝區和接收緩衝區是相同的。這稱爲緩衝區別(請參閱Mvapich2 buffer aliasing),而必須使用標誌MPI_IN_PLACE(請參閱How does MPI_IN_PLACE work with MPI_Scatter?)。上面的代碼被相應地修改。對不起,以前的答案是不完整的!

+0

仍然收到錯誤。 – DeepSidhu1313