2012-10-03 5 views
0

나는 순서가 맞지 않는 통신을하려고합니다. 기본적으로 정수 ID로 식별되는 같은 크기의 부동 소수점 배열이 여러 개 있습니다. 그것은 많은 어레이가 정확하게 방법을 알고, 따라서 RECVS의 정확한 수를 설정하는 수신 측에두 개의 MPI 메시지를 묶을 수 있습니까?

<int id><float array data> 

: 같은

각 메시지가 보일 것입니다. 메시지를 받으면 ID를 분석하여 데이터를 올바른 위치에 넣습니다. 문제는 메시지가 다른 프로세스에서 수신 프로세스로 전송 될 수 있다는 것입니다. (예 : 생산자는 작업 대기열 구조를 가지고 있고 큐에서 사용할 수있는 ID를 처리합니다.)

MPI는 주문 전달에서 P2P 만 보장하므로 정수 ID와 FP 데이터를 간단히 두 개의 메시지에 넣을 수 없습니다. 수신기가 ID와 데이터를 일치시킬 수 없습니다. MPI는 한 번의 전송에서도 두 가지 유형의 데이터를 허용하지 않습니다.

나는 두 가지 접근법 만 생각할 수 있습니다.

1) 수신자는 크기 m (source [m])의 배열을 갖고, m은 송신 노드 수입니다. 보낸 사람이 먼저 ID를 보낸 다음 데이터를 보냅니다. 수신자는 송신자 i로부터 정수 메시지를 수신 한 후 id를 source [i]에 저장합니다. 송신자 i에서 FP 배열을 수신하면 소스 [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를 사용하고 "should"태그가 작동하지만, 코드에서 지정한대로 작동하지 않는다는 것에 동의합니다. 이번에는 내 자신의 데이터 형식을 시도 할 것입니다. 감사! – 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을 사용하고있는 유일한 차이점과 내가 가지고있는 현재의 구현이며, 데이터의 총량입니다 3,000 ~ 3,000 건으로 전달되는 GB 주문. 센드 ID가 실제로 고장난 경우에는 이상하게도 교착 상태가 발생합니다. 일부 전송은 진행할 수 없습니다. 수신자에게 태그가 설정되는 순서대로 발신자를 동기화하면 교착 상태가 사라집니다. doc에서 각 태그에 대해 하나의 일치하는 send/recv가 있으므로 어느 쪽이든 교착 상태가 발생하지 않아야합니다. 그래서 메시지를 묶고 ANY_SOURCE 및 ANY_TAG 구현을 시도합니다. – wujj123456

+0

코드에 다른 동기화 메커니즘이 없으므로 MPI send/recv에서 교착 상태가 발생합니다. Isend/irecv는 내부 버퍼 공간을 소비하지 않습니다.태그는 송신자와 수신자간에 완벽하게 일치합니다. 사실, 교착 상태는 보낸 사람이 일을 크게 잘못 보내는 경우에만 나타납니다. 필자는 MPI 사양에 위배되는이 동작에 대해 추론하기 위해 openMPI 구현에 대한 충분한 지식이 없습니다. – wujj123456

+2

MPI 표준은 '0'부터 'MPI_TAG_UB'까지의 MPI_TAG_UB가 최소 32767 인 허용 가능한 태그 값을 요구합니다. 일부 구현은 'MPI_TAG_UB'(예 : 2^31-1)에 더 높은 값을 제공하지만 다른 것은 '티. 32768 개가 넘는 배열 ID가 사용되는 경우 태그를 사용하여 배열을 식별하는 코드는 이식 가능하지 않습니다. –

관련 문제