2012-10-03 66 views
0

我正在嘗試進行全無止境的溝通。基本上我有多個相同大小的浮點數組,由整數ID標識。我可以捆綁兩條MPI消息嗎?

應該是每一個消息,如:

<int id><float array data> 

在接收端,它知道很多陣列究竟如何在那裏,從而建立RECVS的確切人數。收到消息後,它會解析該ID並將數據放入正確的位置。問題是可以從任何其他進程向接收進程發送消息。 (例如,生產者具有工作隊列結構,並且處理隊列中可用的任何ID)

由於MPI僅保證P2P在訂單遞送中,我不能在兩個消息中平分地放置整數ID和FP數據,否則接收器可能無法將id與數據匹配。 MPI不允許一次發送兩種類型的數據。

我只能想到兩種方法。

1)Receiver有一個大小爲m(source [m])的數組,m是發送節點的數量。發件人先發送id,然後發送數據。接收者在收到來自發件人i的整數消息後將id保存到源[i]。在收到來自發件人i的FP數組後,它會檢查source [i],獲取id並將數據移動到正確的位置。它的工作原理是MPI保證有序的P2P通信。它要求接收者保存每個發送者的狀態信息。更糟糕的是,如果一個發送進程可以在數據之前發送兩個id(例如多線程),則此機制將不起作用。

2)將id和FP視爲字節,並將它們複製到發送緩衝區中。將它們作爲MPI_CHAR發送,然後接收器將它們轉換回整數和FP數組。然後我需要支付複製東西到發送方的字節緩衝區的附加成本。隨着我在MPI進程中增加線程數量,總臨時緩衝區也會增長。

它們都不是完美的解決方案。我不想在進程中鎖定任何內容。我想知道你們有沒有更好的建議。

編輯:代碼將在包含infiniband的共享羣集上運行。機器將被隨機分配。所以我不認爲TCP套接字可以幫助我。另外,IPoIB看起來很貴。我確實需要完整的40Gbps速度進行通信,並讓CPU進行計算。

回答

3

正如有人已經寫了,你可以使用MPI_ANY_SOURCE從任何來源獲得。要發送兩種不同類型的數據在一個單一的發送,你可以使用一個derived datatype

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

#define asize 10 

typedef struct data_ { 
    int id; 
    float array[asize]; 
} data; 

int main() { 

    MPI_Init(NULL,NULL); 

    int rank = -1; 
    int size = -1; 
    MPI_Comm_rank(MPI_COMM_WORLD,&rank); 
    MPI_Comm_size(MPI_COMM_WORLD,&size); 

    data buffer;  
// Define and commit a new datatype 
    int   blocklength [2]; 
    MPI_Aint  displacement[2]; 
    MPI_Datatype datatypes [2]; 
    MPI_Datatype mpi_tdata; 

    MPI_Aint  startid,startarray; 
    MPI_Get_address(&(buffer.id),&startid); 
    MPI_Get_address(&(buffer.array[0]),&startarray); 

    blocklength [0] = 1; 
    blocklength [1] = asize; 
    displacement[0] = 0; 
    displacement[1] = startarray - startid; 
    datatypes [0] = MPI_INT; 
    datatypes [1] = MPI_FLOAT; 

    MPI_Type_create_struct(2,blocklength,displacement,datatypes,&mpi_tdata); 
    MPI_Type_commit(&mpi_tdata); 

    if (rank == 0) { 
    int  count = 0; 
    MPI_Status status; 

    while (count < size-1) { 
     // Non-blocking receive 
     printf("Receiving message %d\n",count); 
     MPI_Recv(&buffer,1,mpi_tdata,MPI_ANY_SOURCE,0,MPI_COMM_WORLD,&status); 
     printf("Message tag %d, first entry %g\n",buffer.id,buffer.array[0]); 
     // Counting the received messages 
     count++; 
    } 

    } else { 
    // Initialize buffer to be sent 
    buffer.id = rank; 
    for (int ii = 0; ii < size; ii++) { 
     buffer.array[ii] = 10*rank + ii; 
    } 
    // Send buffer 
    MPI_Send(&buffer,1,mpi_tdata,0,0,MPI_COMM_WORLD); 
    } 

    MPI_Type_free(&mpi_tdata); 

    MPI_Finalize(); 
    return 0; 
} 
+1

我同意使用MPI_ANY_SOURCE和標籤「應該」工作,但它不符合我的代碼中指定的行爲。這次我會嘗試自己的數據類型。謝謝! – wujj123456

+1

你提出的建議是非常不可移植的,並且不適用於異構環境。一種便攜式的解決方案是使用兩個字段來註冊一個MPI結構類型,MPI_INT類型和塊長度爲1,MPI_FLOAT類型和塊長度爲asize。 –

+1

@HristoIliev你是對的。現在問題應該得到解決。 – Massimiliano

3

您可以在接收函數中指定MPI_ANY_SOURCE作爲源排名,然後使用它們的標記排序消息,這比創建自定義消息更容易。這裏有一個簡單的例子:

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

int main() { 
    MPI_Init(NULL,NULL); 
    int rank=0; 
    int size=1; 
    MPI_Comm_rank(MPI_COMM_WORLD,&rank); 
    MPI_Comm_size(MPI_COMM_WORLD,&size); 

    // Receiver is the last node for simplicity in the arrays 
    if (rank == size-1) { 
     // Receiver has size-1 slots 
     float data[size-1]; 
     MPI_Request request[size-1]; 

     // Use tags to sort receives 
     for (int tag=0;tag<size-1;++tag){ 
      printf("Receiver for id %d\n",tag); 
      // Non-blocking receive 
      MPI_Irecv(data+tag,1,MPI_FLOAT, 
         MPI_ANY_SOURCE,tag,MPI_COMM_WORLD,&request[tag]); 
     } 

     // Wait for all requests to complete 
     printf("Waiting...\n"); 
     MPI_Waitall(size-1,request,MPI_STATUSES_IGNORE); 
     for (size_t i=0;i<size-1;++i){ 
      printf("%f\n",data[i]); 
     } 
    } else { 
     // Producer 
     int id = rank; 
     float data = rank; 
     printf("Sending {%d}{%f}\n",id,data); 
     MPI_Send(&data,1,MPI_FLOAT,size-1,id,MPI_COMM_WORLD); 
    } 

    return MPI_Finalize(); 
} 
+0

這實際上是當前實現我,與我使用Isend生產者的唯一差別,數據的總量按照GB的順序,這是在〜3000發送。如果發送ID實際上不符合要求,則發生奇怪的死鎖,有些發送無法繼續。如果我讓發件人按照接收器中標籤的設置順序發送郵件,死鎖就會消失。從doc,任何一種方式都不應該死鎖,因爲每個標籤只有一個匹配的send/recv。這就是爲什麼我想將郵件打包在一起並嘗試使用ANY_SOURCE和ANY_TAG的原因。 – wujj123456

+0

我相信死鎖來自MPI send/recv,因爲代碼沒有任何其他同步機制。 Isend/irecv不佔用內部緩衝區空間。發送者和接收者之間的標籤完美匹配。事實上,如果發送者亂送亂七八糟的事情,僵局只會表現出來。我沒有足夠的關於openMPI實現的知識來推斷這種違反MPI規範的行爲。 – wujj123456

+2

請注意,MPI標準要求可接受的標記值從「0」到「MPI_TAG_UB」,其中「MPI_TAG_UB」至少爲32767.某些實現爲「MPI_TAG_UB」提供了更高的值(例如2^31-1) 「T。如果使用多於32768個數組ID,則使用標籤識別數組的代碼將不可移植。 –

相關問題