2012-05-28 30 views
10

我正在嘗試使用MPI編寫矩陣向量乘法程序。我試圖發送矩陣的列來分離進程並在本地計算結果。最後我做了MPI_Reduce使用MPI_SUM操作。使用MPI_Scatter發送矩陣列

發送矩陣的行很容易,因爲C按行主要順序存儲數組,但列不是(如果不逐一發送)。我讀到這裏的問題是:

MPI_Scatter - sending columns of 2D array

喬納森·德西使用新的MPI數據類型建議和這裏就是我已經適應了他的代碼,以我自己的需要做:

double matrix[10][10]; 
    double mytype[10][10]; 
    int part_size; // stores how many cols a process needs to work on 
    MPI_Datatype col, coltype; 
    // ... 
    MPI_Type_vector(N, 1, N, MPI_DOUBLE, &col); 
    MPI_Type_commit(&col); 
    MPI_Type_create_resized(col, 0, 1*sizeof(double), &coltype); 
    MPI_Type_commit(&coltype); 
    // ... 
    MPI_Scatter(matrix, part_size, coltype, 
       mypart, part_size, coltype, 
       0, MPI_COMM_WORLD); 

    // calculations... 
    MPI_Reduce(local_result, global_result, 
      N, MPI_DOUBLE, 
      MPI_SUM, 
      0, MPI_COMM_WORLD); 

這工作完全,但我不能說我真的明白它是如何工作的。

  1. MPI_Type_vector如何存儲在內存中?
  2. MPI_Type_create_resized()如何工作,它到底做了什麼?

請注意,我是MPI的初學者。提前致謝。

+2

+1表示它是功課。 :) – solvingPuzzles

+0

@hattenn請不要再使用[作業]標籤。它已被棄用。 [看標籤本身來證實這一點](http://stackoverflow.com/questions/tagged/homework) –

回答

28

my answerthis question對這個問題有很長的描述:很多人都有這些問題的事實證明,這並不明顯,這些想法需要一些習慣。

重要的是知道MPI數據類型描述的內存佈局。主叫序列MPI_Type_vector是:

int MPI_Type_vector(int count, 
        int blocklength, 
        int stride, 
        MPI_Datatype old_type, 
        MPI_Datatype *newtype_p) 

它創建了一個新的類型,它描述的內存佈局,每一個stride項目,還有的blocklength項目塊拔出,共計這些塊的count。這裏的項目以old_type爲單位。因此,舉例來說,如果你叫(這裏命名的參數,你也不會在C實際上做,但:)

MPI_Type_vector(count=3, blocklength=2, stride=5, old_type=MPI_INT, &newtype); 

然後newtype會在內存中描述的佈局是這樣的:

|<----->| block length 

    +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 
    | X | X | | | | X | X | | | | X | X | | | | 
    +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 

    |<---- stride ----->| 

    count = 3 

其中每個正方形是一個整數大小的內存塊,大概是4個字節。請注意,步幅是從一個塊的開始到下一個的開始的整數距離,而不是塊之間的距離。

好了,你的情況,你叫

MPI_Type_vector(N, 1, N, MPI_DOUBLE, &col); 

將於count = N塊,每塊大小爲blocklength=1MPI_DOUBLE S,與stride=NMPI_DOUBLE s各自塊的開始之間的空間。換句話說,它會每N次加倍,總共N次;非常適用於從連續存儲的NxN陣列中提取一列。方便的檢查是查看有多少數據正在被掃描(count*stride = N*N這是矩陣的全部大小,檢查)以及實際包含多少數據(count*blocksize = N,這是一列的大小,檢查。)

如果您只需調用MPI_Send和MPI_Recv來交換各個列,那麼您就完成了;你可以使用這種類型來描述列的佈局,你會沒事的。但還有一件事。

你想調用MPI_Scatter,它發送第一個coltype(比如說)到處理器0,下一個coltype到處理器1等等。如果你用一個簡單的1d數組來做這件事,很容易找出「下一個」數據類型是;如果你將1 int分配給每個處理器,則在第一個int結束後立即開始「next」int。

但新coltype列有一個總extent從柱開始進入N*NMPI_DOUBLE晚節 - 如果MPI_Scatter遵循同樣的邏輯(它),它將開始外面尋找「下一個」列矩陣的內存完全存儲,下一個和下一個等等。你不但不會得到你想要的答案,該計劃可能會崩潰。

解決這個問題的方法是告訴MPI,這個數據類型的「大小」是用於計算「下一個」所在的位置的內存大小,它是一列開始和下一列開始之間的內存大小;也就是說,只有一個MPI_DOUBLE。這並不影響發送的數據量,它仍然是1列數據;它隻影響「下一個在線」計算。使用數組中的列(或行),您可以將此大小發送到內存中適當的步長,並且MPI將選擇正確的下一列發送。沒有這個調整大小的操作符,你的程序可能會崩潰。

當您有更復雜的數據佈局時,如上面鏈接的2d數組示例中的2d塊,則「下一個」項之間沒有任何單個步長;您仍然需要執行調整大小的技巧以使大小成爲某個有用的單位,但是您需要使用MPI_Scatterv而不是使用分散來明確指定要發送的位置。

+1

這是我在stackoverflow上得到的最清晰的答案之一,非常感謝。現在很清楚。如果可以,我會投票100次:) – hattenn

+0

愛丁堡並行計算中心爲我們提供了一個矩陣的二維散點圖的例子,該矩陣使用了'MPI_Type_create_struct'和'MPI_UB'僞類型來設置上界等於一個矩陣元素的大小(他們說這是一個可怕的黑客攻擊)。我想知道他們爲什麼不使用'MPI_Type_create_resized()'代替 - 它應該在2003年左右的Sun MPI中實現。 –

+0

我認爲有時候演講會的人更新幻燈片的頻率比開發人員更新代碼的次數少得多;我知道我有時會犯過一些過時的例子,比過去的日期最好。 –