MPI Fortran 编译器优化错误

MPI Fortran compiler optimization error

尽管在三维数组上编写了复杂的 send/receives 长的、高度并行化的代码,但这个包含二维整数数组的简单代码让我束手无策。我梳理了 Whosebug 的可能解决方案,发现了一个与我遇到的问题略有相似的解决方案:

Boost.MPI: What's received isn't what was sent!

然而,解决方案似乎指出循环代码段是覆盖内存部分的罪魁祸首。但这一个似乎甚至表现得更st运行ger。也许这是我对一些简单细节的粗心疏忽。问题在于以下代码:

program main
implicit none

include 'mpif.h'

integer :: i, j
integer :: counter, offset
integer :: rank, ierr, stVal
integer, dimension(10, 10) :: passMat, prntMat      !! passMat CONTAINS VALUES TO BE PASSED TO prntMat

call MPI_INIT(ierr)
call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr)

counter = 0
offset = (rank + 1)*300
do j = 1, 10
    do i = 1, 10
        prntMat(i, j) = 10                          !! prntMat OF BOTH RANKS CONTAIN 10
        passMat(i, j) = offset + counter            !! passMat OF rank=0 CONTAINS 300..399 AND rank=1 CONTAINS 600..699
        counter = counter + 1
    end do
end do

if (rank == 1) then
    call MPI_SEND(passMat(1:10, 1:10), 100, MPI_INTEGER, 0, 1, MPI_COMM_WORLD, ierr)    !! SEND passMat OF rank=1 to rank=0
else
    call MPI_RECV(prntMat(1:10, 1:10), 100, MPI_INTEGER, 1, 1, MPI_COMM_WORLD, stVal, ierr)
    do i = 1, 10
        print *, prntMat(:, i)
    end do
end if

call MPI_FINALIZE(ierr)
end program main

当我使用没有标志的 mpif90 编译代码并在我的机器上使用 mpi运行 -np 2 运行 编译代码时,我得到以下输出,前四个索引中的值错误数组:

0 0 400 0 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699

但是,当我使用相同的编译器编译它但启用了 -O3 标志时,我得到了正确的输出:

600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699

此错误与机器有关。这个问题只出现在我的系统 运行ning Ubuntu 14.04.2,使用 OpenMPI 1.6.5

我在其他系统 运行ning RedHat 和 CentOS 以及代码 运行 上尝试过此操作,无论是否使用 -O3 标志。奇怪的是,这些机器使用旧版本的 OpenMPI - 1.4

我猜测 -O3 标志正在执行一些奇怪的优化,它正在修改数组在进程之间传递的方式。

我也试过其他版本的数组分配。上面的代码使用显式形状数组。使用假设的形状和分配的数组,我得到的结果是一样的,如果不是更奇怪的话,其中一些是段错误的。我尝试使用 Valgrind 来追踪这些段错误的起源,但我仍然没有掌握让 Valgrind 在 运行 MPI 程序时不给出误报的窍门。

我相信解决上述代码的性能差异将有助于我理解其他代码的发脾气。

如有任何帮助,我们将不胜感激!这段代码真的让我怀疑我写的所有其他 MPI 代码是否都正确。

将 Fortran 90 接口用于 MPI 显示您对 MPI_RECV

的调用不匹配
      call MPI_RECV(prntMat(1:10, 1:10), 100, MPI_INTEGER, 1, 1, MPI_COMM_WORLD, stVal, ierr)
                                                                                            1
Error: There is no specific subroutine for the generic ‘mpi_recv’ at (1)

这是因为状态变量 stVal 是一个 integer 标量,而不是 MPI_STATUS_SIZE 的数组。 F77接口(include 'mpif.h')到MPI_RECV是:

INCLUDE ’mpif.h’
MPI_RECV(BUF, COUNT, DATATYPE, SOURCE, TAG, COMM, STATUS, IERROR)
<type>    BUF(*)
INTEGER    COUNT, DATATYPE, SOURCE, TAG, COMM
INTEGER    STATUS(MPI_STATUS_SIZE), IERROR

改变

integer :: rank, ierr, stVal

integer :: rank, ierr, stVal(mpi_status_size)

生成一个按预期工作的程序,已使用 gfortran 5.1 和 OpenMPI 1.8.5 进行测试。

使用 F90 接口(use mpi vs include "mpif.h")让编译器在编译时检测不匹配的参数,而不是产生令人困惑的运行时问题。