2015-06-30 45 views
0

我有一個奇怪的問題與C型結構有關,它是在MPI派生數據類型的幫助下傳遞的。下面的例子工作;它只是發送一個包含一個integer加上4 float值的消息。MPI派生數據類型適用於浮點數,但不適用於雙精度浮點數。這是一個對齊問題?

Minmum工作示例:

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

int main(int argc, char *argv[]) { 
    MPI_Init(&argc, &argv); 

    int i, rank, tag = 1; 
    MPI_Status status; 
    MPI_Comm_rank(MPI_COMM_WORLD, &rank); 

    // Array of doubles plus element count 
    typedef struct { 
     int row; 
     float elements[4]; 
    } My_array; 

    // Derived datatype for an array of doubles plus element count 
    MPI_Datatype MY_ARRAY_TYPE; 
    const int nr_blocks = 2; 
    int blocklengths[2] = {1, 4}; 
    MPI_Datatype oldtypes[2] = {MPI_INT, MPI_FLOAT}; 
    MPI_Aint extent, lb; 
    MPI_Type_get_extent(MPI_INT, &lb, &extent); 
    MPI_Aint displacements[2] = {0, extent}; 
    MPI_Type_create_struct(nr_blocks, blocklengths, displacements, 
         oldtypes, &MY_ARRAY_TYPE); 
    MPI_Type_commit(&MY_ARRAY_TYPE); 

    if(rank == 0) { 
     My_array array1 = {3, 3.1, 3.2, 3.3, 3.4}; 
     MPI_Send(&array1, 1, MY_ARRAY_TYPE, 1, tag, MPI_COMM_WORLD); 
    } 
    if(rank == 1) { 
     My_array array2; 
     MPI_Recv(&array2, 1, MY_ARRAY_TYPE, 0, tag, MPI_COMM_WORLD, &status); 
     printf("Rank %d received elements of row %d:\n", rank, array2.row); 
     for(i = 0; i < 4; i++) 
      printf("\t%.1f\n", array2.elements[i]); 
    } 
    MPI_Type_free(&MY_ARRAY_TYPE); 
    MPI_Finalize(); 
} 

如果你有機會到MPI安裝,例如可以通過mpicc -o example example.c編譯和運行mpirun -np 2 example。 輸出應該

Rank 1 received elements of row 3: 
    3.1 
    3.2 
    3.3 
    3.4 

問題: 現在當float在數組變化爲double秒的陣列,並相應地對MPI_FLOATMPI_DOUBLE,我得到一個錯誤的結果。

此代碼:

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

int main(int argc, char *argv[]) { 
    MPI_Init(&argc, &argv); 

    int i, rank, tag = 1; 
    MPI_Status status; 
    MPI_Comm_rank(MPI_COMM_WORLD, &rank); 

    // Array of doubles plus element count 
    typedef struct { 
     int row; 
     double elements[4]; 
    } My_array; 

    // Derived datatype for an array of doubles plus element count 
    MPI_Datatype MY_ARRAY_TYPE; 
    const int nr_blocks = 2; 
    int blocklengths[2] = {1, 4}; 
    MPI_Datatype oldtypes[2] = {MPI_INT, MPI_DOUBLE}; 
    MPI_Aint extent, lb; 
    MPI_Type_get_extent(MPI_INT, &lb, &extent); 
    MPI_Aint displacements[2] = {0, extent}; 
    MPI_Type_create_struct(nr_blocks, blocklengths, displacements, 
         oldtypes, &MY_ARRAY_TYPE); 
    MPI_Type_commit(&MY_ARRAY_TYPE); 

    if(rank == 0) { 
     My_array array1 = {3, 3.1, 3.2, 3.3, 3.4}; 
     MPI_Send(&array1, 1, MY_ARRAY_TYPE, 1, tag, MPI_COMM_WORLD); 
    } 
    if(rank == 1) { 
     My_array array2; 
     MPI_Recv(&array2, 1, MY_ARRAY_TYPE, 0, tag, MPI_COMM_WORLD, &status); 
     printf("Rank %d received elements of row %d:\n", rank, array2.row); 
     for(i = 0; i < 4; i++) 
      printf("\t%.1f\n", array2.elements[i]); 
    } 
    MPI_Type_free(&MY_ARRAY_TYPE); 
    MPI_Finalize(); 
} 

生產:

Rank 1 received elements of row 3: 
    3.1 
    3.2 
    3.3 
    0.0 

我試圖圍繞一個位,在該結構和所導出的數據類型使用其它數據(例如,整數,而不是僅僅一個的陣列,int/MPI_INT而不是float/MPI_FLOAT等),並且發現問題只在使用雙打時出現。這讓我懷疑這可能是一種排列問題 - 但我被困在那裏。 MPI應自動處理對齊。

問:爲什麼用float/MPI_FLOAT上面的例子中工作,但不與double/MPI_DOUBLE,我該如何解決?

一些機細節,可能是相關的:

  • CPU:AMD皓龍6134
  • 地址尺寸:48位
  • 陣營:64
  • 編譯器:GCC 4.4.7
  • MPI庫:(不幸)供應商特定

編輯:as su在弗拉基米爾F的評論中,我添加了不起作用的代碼。

+2

最好顯示導致錯誤的代碼,以避免任何可能的不確定性,並對其進行測試。當您不顯示導致代碼的確切錯誤時,可能會隱藏一個微妙的問題。 –

+0

嘗試使用lf不打印的打印雙打... – Jeff

回答

1

我剛剛發現問題是什麼:它確實是對齊的。第二個代碼清單正確地產生前三個雙打只不過是一個奇怪的巧合......通過使用MPI_INT的擴展作爲以下值的偏移量,我假定不會有填充。這是更好地計算這樣的偏移:

#include <stddef.c> 
... 
MPI_Datatype MY_ARRAY_TYPE; 
const int nr_blocks = 2; 
int blocklengths[2] = {1, 4}; 
MPI_Datatype oldtypes[2] = {MPI_INT, MPI_DOUBLE}; 
MPI_Aint displacements[2]; 
displacements[0] = offsetof(My_array, row); 
displacements[1] = offsetof(My_array, elements); 
MPI_Type_create_struct(nr_blocks, blocklengths, displacements, 
        oldtypes, &MY_ARRAY_TYPE); 
MPI_Type_commit(&MY_ARRAY_TYPE); 
... 

我真的有興趣看看它是如何制定出這樣......爲什麼我們得到3層正確的價值觀和一個0.0≦由於我的平臺上的對齊關閉了4個字節,雙打表示了8個字節,爲什麼我沒有得到一些隨機數?如果前3個字節每個都取一個雙精度值的低4個字節加上下4個雙精度值的高4個數字,那麼它們如何正確解碼?

+0

雙打中的高位是零,不是?嘗試設置爲MAX_DBL(?)並查看是否更改了結果。 – Jeff

相關問題