2011-03-20 18 views
6

說2個進程正在參與。流程0(等級0)具有如何從處理器獲取MPI_Gatherv列,其中每個進程可能發送不同數量的列

A = { a d 
     b e 
     c f 
    } 

和處理1(等級1)具有

A = { g 
     h 
     i 
    } 

我想兩個處理器來發送這些列序號爲0,這樣等級0將在下面說另一個2D陣列。

B = { a d g 
     b e h 
     c f i 
    } 

我創建了MPI_Gatherv新列的數據類型,並正嘗試下面的代碼,這讓我沒有在那裏。

我的具體問題是:

  1. 我應該如何處理這一
  2. 應該是什麼send_type和recv_type。
  3. 應該如何規定的位移(如果他們在新的數據類型或MPI_CHAR期限)

感謝。

這是我的代碼:

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

int main(int argc, char *argv[]) 
{ 
    int numprocs, my_rank; 
    long int i, j; 
    MPI_Status status; 
    char **A; 
    char **B; 
    MPI_Init(&argc, &argv); 
    MPI_Comm_size(MPI_COMM_WORLD, &numprocs); 
    MPI_Comm_rank(MPI_COMM_WORLD, &my_rank); 

    if(my_rank == 0) 
    { 
    A = (char **)calloc((3), sizeof(char *)); 
    B = (char **)calloc((3), sizeof(char *)); 
    for(i=0; i<3; ++i) 
    { 
     A[i] = (char *)calloc(2, sizeof(char)); 
     B[i] = (char *)calloc(3, sizeof(char)); 
    } 

    A[0][0] = 'a'; 
    A[1][0] = 'b'; 
    A[2][0] = 'c'; 
    A[0][1] = 'd'; 
    A[1][1] = 'e'; 
    A[2][1] = 'f'; 
    } 
    else 
    { 
    A = (char **)calloc((3), sizeof(char *)); 
    for(i=0; i<3; ++i) 
    { 
     A[i] = (char *)calloc(1, sizeof(char)); 
    } 
    A[0][0] = 'g'; 
    A[1][0] = 'h'; 
    A[2][0] = 'i'; 

    } 
    MPI_Datatype b_col_type; 
    MPI_Type_vector(3, 1, 1, MPI_CHAR, &b_col_type); 
    MPI_Type_commit(&b_col_type); 
    int displs[2] = {0, 2}; 
    int recvcounts[2] = {2, 1}; 
    MPI_Gatherv(&A[0][0], recvcounts[my_rank], b_col_type, &B[0][0], recvcounts, displs, b_col_type, 0, MPI_COMM_WORLD); 
    if(my_rank == 0) 
    { 
    for(i=0; i<3; ++i) 
    { 
     for(j=0; j<3; ++j) 
     printf("%c ", B[i][j]); 
     printf("\n"); 
    } 
    } 
    MPI_Finalize(); 
    return 0; 
} 
+0

你是什麼意思「它讓你無處」?確切的問題是什麼? – suszterpatt 2011-03-20 23:29:31

+0

所以,如果我嘗試運行上面的代碼,在到B得到的東西只是 $的mpirun -np 2 try_gather 一個d 所以只有排名0能夠發送它的2個元素。我試着調整了displs和recvcounts的值,但是我無法得到我想要的結果。目前的代碼至少有2個字符在正確的地方。 我放棄嘗試在註釋部分中設置代碼的格式。基本上'a'和'd'去正確的地方。休息都是空白在陣列B. – Reep 2011-03-20 23:57:10

回答

6

所以第一關 - 這又發表了MPI和C數組所有的時間 - 你不能真正做到標準C二維數組的事情。讓我們來看看這個:

A = (char **)calloc((3), sizeof(char *)); 
for(i=0; i<3; ++i) 
{ 
    A[i] = (char *)calloc(2, sizeof(char)); 
} 

這一定會分配字符的3x2的陣列,但是你不知道所得到的數據是如何在內存佈局。特別是,全部不保證A[1][0]緊跟在A[0][1]之後。這使得創建跨越數據結構的MPI數據類型非常困難!您需要分配3x2的連續字節,然後使陣列點進去:

char **charalloc2d(int n, int m) { 
    char *data = (char *)calloc(n*m,sizeof(char)); 
    char **array = (char **)calloc(n, sizeof(char *)); 
    for (int i=0; i<n; i++) 
     array[i] = &(data[i*m]); 

    return array; 
} 

void charfree2d(char **array) { 
    free(array[0]); 
    free(array); 
    return; 
} 

/* ... */ 
nrows = 3; 
ncols = 2; 
A = charalloc2d(nrows,ncols); 

現在我們知道一些關於陣列的佈局,並可以依靠,要建立數據類型。

你在正確的軌道上的數據類型上 -

MPI_Datatype b_col_type; 
MPI_Type_vector(3, 1, 1, MPI_CHAR, &b_col_type); 
MPI_Type_commit(&b_col_type); 

MPI_Type_vector的簽名(計數,blocklen,步幅,OLD_TYPE,* NEWTYPE)。
我們想要nrows個字符,它們是以1個塊爲單位的;但他們分開ncols;所以這是邁步。

請注意,這實際上是A陣列的列類型,而不是B;該類型將取決於數組中的列數。所以每個進程都使用不同的sendtype,這很好。

MPI_Datatype a_col_type; 
MPI_Type_vector(nrows, 1, ncols, MPI_CHAR, &a_col_type); 
MPI_Type_commit(&a_col_type); 

最後一步是MPI_Gatherv,在這裏你必須要有點可愛。訣竅是,我們想要一次發送(並接收)多個這些東西 - 也就是多個連續的東西。但是,我們需要下一個專欄,不要把ncols字符刪掉,而只是刪掉一個字符。幸運的是,我們可以通過將數據結構的上限設置爲距下限一個字符,以便下一個元素在正確的位置開始。這是the standard所允許的,實際上它們在4.1.4節中的一個例子取決於它。

爲了做到這一點,我們創建啓動後結束只是一個字節一個調整大小類型:

MPI_Type_create_resized(a_col_type, 0, 1*sizeof(char), &new_a_col_type); 
MPI_Type_commit(&new_a_col_type); 

,類似的還有B;現在我們可以按照人們的期望發送和接收這些數字的倍數。所以以下適用於我:

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

char **charalloc2d(int n, int m) { 
    char *data = (char *)calloc(n*m,sizeof(char)); 
    char **array = (char **)calloc(n, sizeof(char *)); 
    for (int i=0; i<n; i++) 
     array[i] = &(data[i*m]); 

    return array; 
} 

void charfree2d(char **array) { 
    free(array[0]); 
    free(array); 
    return; 
} 


int main(int argc, char *argv[]) 
{ 
    int numprocs, my_rank; 
    int nrows, ncols, totncols; 
    long int i, j; 
    char **A; 
    char **B; 
    MPI_Init(&argc, &argv); 
    MPI_Comm_size(MPI_COMM_WORLD, &numprocs); 
    MPI_Comm_rank(MPI_COMM_WORLD, &my_rank); 

    if(my_rank == 0) 
    { 
     nrows=3; 
     ncols=2; 
     totncols = 3; 

     A = charalloc2d(nrows, ncols); 
     B = charalloc2d(nrows, totncols); 

     A[0][0] = 'a'; 
     A[1][0] = 'b'; 
     A[2][0] = 'c'; 
     A[0][1] = 'd'; 
     A[1][1] = 'e'; 
     A[2][1] = 'f'; 
    } 
    else 
    { 
     nrows = 3; 
     ncols = 1; 
     A = charalloc2d(nrows, ncols); 
     B = charalloc2d(1,1); /* just so gatherv survives */ 
     A[0][0] = 'g'; 
     A[1][0] = 'h'; 
     A[2][0] = 'i'; 

    } 
    MPI_Datatype a_col_type, new_a_col_type; 
    MPI_Type_vector(nrows, 1, ncols, MPI_CHAR, &a_col_type); 
    MPI_Type_commit(&a_col_type); 

    /* make the type have extent 1 character -- now the next 
    * column starts in the next character of the array 
    */ 
    MPI_Type_create_resized(a_col_type, 0, 1*sizeof(char), &new_a_col_type); 
    MPI_Type_commit(&new_a_col_type); 

    MPI_Datatype b_col_type, new_b_col_type; 
    if (my_rank == 0) { 
     MPI_Type_vector(nrows, 1, totncols, MPI_CHAR, &b_col_type); 
     MPI_Type_commit(&b_col_type); 

     /* similarly "resize" b columns */ 
     MPI_Type_create_resized(b_col_type, 0, 1*sizeof(char), &new_b_col_type); 
     MPI_Type_commit(&new_b_col_type); 
    } 

    int displs[2] = {0, 2}; 
    int recvcounts[2] = {2, 1}; 
    MPI_Gatherv(A[0], recvcounts[my_rank], new_a_col_type, 
       B[0], recvcounts, displs, new_b_col_type, 
       0, MPI_COMM_WORLD); 
    if(my_rank == 0) 
    { 
     for(i=0; i<3; ++i) 
     { 
      for(j=0; j<3; ++j) 
       printf("%c ", B[i][j]); 
      printf("\n"); 
     } 
    } 
    MPI_Finalize(); 
    return 0; 
} 
+0

謝謝喬恩。後來我意識到我的數組在內存中不是連續的。因此,現在我打算爲每個進程使用具有不同MPI_Datatype的Send/Recv組合,而不使用MPI_Gatherv。我想這也是你所指的呢? – Reep 2011-03-21 04:39:51

+0

將矩陣按主列順序存儲。這樣,單列將是一個簡單的'MPI_Contiguous'數據類型,並且您可以使用'Gatherv()'(來自進程0的2列,位移0,以及來自進程1的1列,位移2)輕鬆發送/接收它們。無論如何,這符合你分解數據的方式。 – suszterpatt 2011-03-21 15:22:49

+0

@suszterpatt我不想以列的主要格式存儲,因爲不同的處理器按行的主要順序將數據計算並存儲到它們的'A [] []'數組中,並且現實中的數組非常大,因此寫入操作可能會導致大量的內存抖動。 – Reep 2011-03-21 20:25:20

相關問題