2013-11-21 2 views
0

MPI_Bcast을 구현하려고합니다. MPI_SendMPI_Recv으로 할 계획이지만 직접 메시지를 보낼 수없는 것 같습니다.MPI가 MPI_Send 및 MPI_Recv로 데이터를 보낼 수 없습니다.

void My_MPI_Bcast(void *buffer, int count, MPI_Datatype datatype, int root, MPI_Comm comm) { 
    int comm_rank, comm_size, i; 
    MPI_Comm_rank(comm, &comm_rank); 
    MPI_Comm_size(comm, &comm_size); 
    if(comm_rank==root){ 
     for(i = 0; i < comm_size; i++){ 
       MPI_Send(buffer, count, datatype, i, 0, comm); 
     } 
    } 
    MPI_Recv(buffer, count, datatype, root, 0, comm, MPI_STATUS_IGNORE); 
    } 

그것에 대한 어떤 제안을 따를

코드는 무엇입니까? 아니면 절대로 메시지를 보내지 말고 그냥 메모리 카피를해야합니까?

+0

내 컴퓨터에서 정상적으로 작동합니다. 포인터/주소를 섞지 않았습니까? – Sleepyhead

+1

@Sleepyhead, 큰 '카운트'로 시도해보십시오. 작은 메시지는 일반적으로 버퍼링되거나 열정적 인 프로토콜을 사용하여 전송됩니다. –

답변

0

는 당신이 그렇지 않으면 아마

1

이 잘못된 프로그램 중단됩니다 만 rank=root에 대한 MPI_Recv(buffer, count, datatype, root, 0, comm, MPI_STATUS_IGNORE);를 넣어한다고 생각합니다. 차단 될 수 있으므로 자신에게 MPI_Send를 차단하는 것에 의존 할 수 없습니다. MPI는 버퍼를 다시 사용할 수있을 때까지 MPI_Send가 반환되는 것을 보증하지 않습니다. 경우에 따라 메시지가 대상에서 수신 될 때까지 차단 될 수도 있습니다. 여러분의 프로그램에서 목적지는 아직 보내려하기 때문에 MPI_Recv를 절대 호출 할 수 없다.

이제 My_MPI_Bcast 예에서 루트 프로세스에 이미 데이터가 있습니다. 왜 그것을 보내거나 복사해야합니까?

2

루트 노드의 MPI_Send/MPI_Recv 블록은 교착 상태 일 수 있습니다.

MPI_Isend로 변환하면이 문제를 해결할 수 있습니다. 그러나 송신 버퍼가 재사용되고 루트가 MPI_Recv에 "일찍"도착할 가능성이 높고 다른 버퍼로 전송되기 전에 버퍼를 변경할 수 있기 때문에 문제가 발생할 수 있습니다. 이것은 특히 대규모 일자리에있을 가능성이 큽니다. 또한이 루틴이 fortran에서 호출되면 각 MPI_Send 호출에서 버퍼가 손상되는 문제가 발생할 수 있습니다.

MPI_Sendrecv는 루트 프로세스에만 사용할 수 있습니다. 이는 루트 프로세스가 전용 MPI_Sendrecv에 들어가기 전에 모든 비 루트 랭크들에 대한 MPI_Send 's를 "완료"(예를 들어, 송신 버퍼가 안전하게 변경 될 수 있음)하게한다. for 루프는 단순히 "0"대신 "1"로 시작하고 MPI_Sendrecv 호출은 해당 루프의 맨 아래에 추가됩니다. (데이터가 "버퍼"에 있고 버퍼링하기 때문에 더 좋은 질문이되는 이유는 무엇입니까?)

그러나이 모든 질문은 왜이 일을 전혀하지 않습니까? 이것이 포인트 투 포인트 (point to point) 통화로 집단을 작성하는 간단한 "학문적 운동"인 경우 그렇게하십시오. 그러나 당신의 접근 방식은 최선의 방법입니다. 이 전반적인 전략은 합리적으로 구현 된 mpi에서 MPI_Bcast 알고리즘 중 하나에 의해 패배합니다.

+0

나는 단지 mpi 튜토리얼을 따라 프로그래밍으로 배우려고 노력한다. – bxshi

3

프로그램이 여러 수준에서 오류가 있습니다.

if(comm_rank=root){ 

comm_rankroot에 비교가 아니라 comm_rankroot를 할당하고 루프 만 root 제로가 아닌 경우 실행하고, 그 이외의 것입니다하지 않습니다 : 우선, 조건에 오류가있다 모든 계급이 처형 할 것이다.

둘째, 루트 프로세스는 데이터가 이미 있으므로 자체로 데이터를 보낼 필요가 없습니다. 그래도 보내고 받기를 원한다고해도 MPI_SendMPI_Recv은 동일한 버퍼 공간을 인식하므로 올바르지 않습니다. 일부 MPI 구현은 자체 상호 작용을 위해 직접 메모리 복사본을 사용합니다. 즉, 라이브러리는 memcpy()을 사용하여 메시지를 전송할 수 있습니다. memcpy()을 중복 버퍼 (동일한 버퍼 사용 포함)와 함께 사용하면 정의되지 않은 동작이 발생합니다.

선형 방송을 구현하는 가장 적절한 방법은 다음과 같습니다

void My_MPI_Bcast(void *buffer, int count, MPI_Datatype datatype, int root, MPI_Comm comm) 
{ 
    int comm_rank, comm_size, i; 
    MPI_Comm_rank(comm, &comm_rank); 
    MPI_Comm_size(comm, &comm_size); 
    if (comm_rank == root) 
    { 
     for (i = 0; i < comm_size; i++) 
     { 
     if (i != comm_rank) 
      MPI_Send(buffer, count, datatype, i, 0, comm); 
     } 
    } 
    else 
     MPI_Recv(buffer, count, datatype, root, 0, comm, MPI_STATUS_IGNORE); 
} 

교착없이 자신에게 이야기하는 프로세스에 대한 일반적인 방법

은 다음과 같습니다

  • MPI_IsendMPI_Recv 또는 이들의 조합의 조합을 사용하여 MPI_SendMPI_Irecv;
  • 버퍼 된 송신 사용 MPI_Bsend;
  • MPI_Sendrecv 또는 MPI_Sendrecv_replace을 사용하십시오.

여러 보내는 경우에 잘 MPI_IrecvMPI_Send 작품의 조합은 당신처럼 루프에서 수행됩니다. 예 :

MPI_Request req; 

// Start a non-blocking receive 
MPI_Irecv(buff2, count, datatype, root, 0, comm, &req); 
// Send to everyone 
for (i = 0; i < comm_size; i++) 
    MPI_Send(buff1, count, datatype, i, 0, comm); 
// Complete the non-blocking receive 
MPI_Wait(&req, MPI_STATUS_IGNORE); 

송신 및 수신에 별도의 버퍼를 사용합니다. 아마도 같은 버퍼를 송신과 수신에 모두 사용할 수있게하는 점대 점 MPI 통신 호출은 집합 MPI 호출의 내부 모드뿐만 아니라 MPI_Sendrecv_replace 일 것입니다. 그러나 이들은 내부적으로 구현되어 같은 시간에 동일한 메모리 영역이 송수신 용으로 사용될 수 없습니다.

+0

예고해 주셔서 감사합니다. 간단한 오류로 다른 사람을 혼란스럽게 만들지 않기 위해 변경했습니다. – bxshi