2017-04-26 11 views
1

좋은 입력 매개 변수를 가진 gfortran 대기 전송 모델 코드에서 MPI_REDUCE 호출로 며칠 동안 싸워 왔지만 마스터의 recvbuf에서 매우 불합리한 결과를 반환합니다. 다음과 같이 나는 간단한 예에서 문제를 복제 할 수있었습니다 :MPI_REDUCE가 1000x1000x6 REAL 배열에 대해 잘못된 답을 반환합니다.

PROGRAM TEST 

    USE mpi 

    IMPLICIT NONE 

    INTEGER my_rank, size, ierror 
    INTEGER, PARAMETER :: nx=1000, ny=1000, nz=6 
    INTEGER :: buffsize 

    REAL, DIMENSION(nx, ny, nz) :: u, v 

    call MPI_INIT(ierror) 
    call MPI_COMM_SIZE(MPI_COMM_WORLD, size, ierror) 
    call MPI_COMM_RANK(MPI_COMM_WORLD, my_rank, ierror) 

    PRINT *, 'my_rank, size: ', my_rank, size 

    buffsize = nx*ny*nz 

    u = my_rank + 1 

    PRINT *, 'PE: ', my_rank, ', Before reduce, SHAPE(u): ', SHAPE(u) 
    PRINT *, 'PE: ', my_rank, ', Before reduce, SUM(u): ', SUM(u) 

    CALL MPI_REDUCE(u, v, buffsize, MPI_REAL, & 
&     MPI_SUM, 0, MPI_COMM_WORLD, ierror) 

    CALL MPI_BARRIER(MPI_COMM_WORLD, ierror) 

    PRINT *, 'PE: ', my_rank, ', after reduce, ierror: ', ierror 
    PRINT *, 'PE: ', my_rank, ', after reduce, SUM(u): ', SUM(u) 
    PRINT *, 'PE: ', my_rank, ', after reduce, SUM(v): ', SUM(v) 

    CALL MPI_FINALIZE(ierror) 

END PROGRAM test 

이 반환

mpirun -np 2 ./test3 
my_rank, size:   0   2 
my_rank, size:   1   2 
PE:   1 , Before reduce, SHAPE(u):   1000  1000   6 
PE:   0 , Before reduce, SHAPE(u):   1000  1000   6 
PE:   0 , Before reduce, SUM(u): 6000000.00  
PE:   1 , Before reduce, SUM(u): 12000000.0  
PE:   0 , after reduce, ierror:   0 
PE:   1 , after reduce, ierror:   0 
PE:   1 , after reduce, SUM(u): 12000000.0  
PE:   0 , after reduce, SUM(u): 6000000.00  
PE:   1 , after reduce, SUM(v): 0.00000000  
PE:   0 , after reduce, SUM(v): 18407592.0  

PE0은 마지막에 SUM (V)로 18000000.0을 보여주는 "해야" 선.

코드에서 nz 매개 변수를 6에서 5로 설정하면 올바른 결과가 생성됩니다. 정말 헷갈리는 점은 gfortran 5.3과 openmpi를 사용하는 AWS EC2 인스턴스, mpich를 사용하는 노트북의 gfortran 5.4, c) openmpi를 사용하는 워크 스테이션의 gfortran 4.4에 동일한 값을 반환한다는 것입니다.

배열의 유형을 DOUBLE PRECISION으로 변경하면 (MPI_REDUCE 호출에서 지정하는 것과 같이) 훨씬 큰 배열의 경우에도 잘 작동합니다. REAL보다는 REAL4를 사용하면 같은 결과가 나옵니다.

나는 이것이 단순해야한다는 것을 알고 있으며 나는 여기서 진짜 바보가되고있다. 그러나 나는 이것을 이해하지 못하고있다. 내 버퍼 크기가 2^31-1보다 작은 정수 값이어야한다는 몇 가지 제안을 읽었습니다.하지만 여기서는 확실합니다.

답변

3

이 MPI와 함께, 그것은 단지 요약 정밀 문제를 아무 상관이 없습니다 :

PROGRAM TEST 
    IMPLICIT NONE 
    INTEGER, PARAMETER :: nx=1000, ny=1000, nz=6 
    REAL, DIMENSION(nx, ny, nz) :: u 
    u = 3 
    PRINT *, SUM(u) 
END PROGRAM test 

이 같은 결과를 반환합니다. 작은 숫자에 큰 숫자를 추가하면 많은 작은 숫자의 합계에 문제가 반올림 될 수 있습니다.이 효과는 중요한 오류로 누적 될 수 있습니다. 이 효과를 막기위한 합계 알고리즘이 있습니다 (예 : Kahan summation). 포트란의 SUM은 이러한 방식으로 구현되지 않았습니다.

+4

Fortran은 실제로'sum'의 작동 방식을 지정하지 않고 결과에 "프로세서에 종속적 인 합계와 같은 값을가집니다"라고 지정합니다. 다른 컴파일러는이 문제를 [이 다른 질문] (https://stackoverflow.com/q/25316371)에서 볼 수있는 것처럼 구현 품질 문제로 간주합니다. – francescalus