MPI -Scatterv增加分割顺序

时间:2017-09-21 08:42:29

标签: mpi

我想用MPI_Scatterv分割不同大小向量的向量。当我选择按降序排列的分区时,代码运行正常,但是当我选择递增顺序时,它会失败。 MPI_Scatterv是否可能仅用于按递减顺序进行分区?我不知道错误在哪里。可以使用的代码以及错误的变体。

program scatt
   include 'mpif.h'
   integer idproc, num, ierr, tag,namelen, status(MPI_STATUS_SIZE),comm
    character *(MPI_MAX_PROCESSOR_NAME) processor_name
    integer, allocatable :: myray(:),send_ray(:)
    integer counts(3),displ(3)
    integer siz,mysize,i,k,j,total
   call MPI_INIT(ierror)
    comm = mpi_comm_world
   call MPI_COMM_SIZE(comm, num, ierror)
   call MPI_COMM_RANK(comm, idproc, ierror)

    siz=12
! create the segmentation in decreasing manner
    counts(1)=5
    counts(2)=4
    counts(3)=3
    displ(1)=0
    displ(2)=5
    displ(3)=9
   allocate(myray(counts(idproc+1)))
myray=0
! create the data to be sent on the root
    if(idproc == 0)then
        !size=count*num
        allocate(send_ray(0:siz-1))
        do i=0,siz
            send_ray(i)=i+1
        enddo
        write(*,*) send_ray
    endif
! send different data to each processor
    call MPI_Scatterv(  send_ray, counts, displ, MPI_INTEGER, &
                        myray, counts,  MPI_INTEGER, &
                        0,comm,ierr)
    write(*,*)"myid= ",idproc," ray= ",myray
   call MPI_FINALIZE(ierr)
   end

结果确定是:

myid=            1  ray=            6           7           8           9
myid=            0  ray=            1           2           3           4           5
myid=            2  ray=           10          11          12

当我在增加分段顺序中编写相同的代码时

 counts(1)=2
 counts(2)=4
 counts(3)=6
 displ(1)=0
 displ(2)=2
 displ(3)=6

仅针对根

进行细分
 myid=            0  ray=            1           2

,错误信息为:

Fatal error in PMPI_Scatterv: Message truncated, error stack:
PMPI_Scatterv(671)......................: MPI_Scatterv(sbuf=(nil), scnts=0x6b4da0, displs=0x6b4db0, MPI_INTEGER, rbuf=0x26024b0,
rcount=2, MPI_INTEGER, root=0, MPI_COMM_WORLD) failed
MPIR_Scatterv_impl(211).................: 
I_MPIR_Scatterv_intra(278)..............: Failure during collective
I_MPIR_Scatterv_intra(272)..............: 
MPIR_Scatterv(147)......................: 
MPIDI_CH3_PktHandler_EagerShortSend(441): Message from rank 0 and tag 6 truncated; 16 bytes received but buffer size is 8
Fatal error in PMPI_Scatterv: Message truncated, error stack:
PMPI_Scatterv(671)................: MPI_Scatterv(sbuf=(nil), scnts=0x6b4da0, displs=0x6b4db0, MPI_INTEGER, rbuf=0x251f4b0, rcount=2, MPI_INTEGER, root=0, MPI_COMM_WORLD) failed
MPIR_Scatterv_impl(211)...........: 
I_MPIR_Scatterv_intra(278)........: Failure during collective
I_MPIR_Scatterv_intra(272)........: 
MPIR_Scatterv(147)................: 
MPIDI_CH3U_Receive_data_found(131): Message from rank 0 and tag 6 truncated; 24 bytes received but buffer size is 8
forrtl: error (69): process interrupted (SIGINT)

1 个答案:

答案 0 :(得分:1)

您的代码中存在两个问题。

首先,调用MPI_Scatterv是错误的。接收缓冲区的大小必须是标量,而不是数组,并且仅在调用列中给出数组的大小。在您的情况下,您需要将第二次出现的counts更改为counts(idproc+1)

call MPI_Scatterv(send_ray, counts, displ,    MPI_INTEGER, &
                  myray,    counts(idproc+1), MPI_INTEGER, &
                  0, comm, ierr)

同样适用于免费操作MPI_Gatherv - 本地发送缓冲区的大小也是标量。

另一个问题是此初始化循环中的越界访问:

    allocate(send_ray(0:siz-1))
    do i=0,siz
        send_ray(i)=i+1
    enddo

此处send_ray分配了边界0:siz-1,但循环从0运行到siz,这是一个超出数组末尾的元素。某些编译器具有启用运行时越界访问检查的选项。例如,对于英特尔Fortran,选项为-check bounds。对于Gfortran,选项为-fcheck=bounds。访问超过其末尾的数组可能会覆盖并因此改变其他数组中的值(最坏情况,难以发现)或破坏堆指针并使程序崩溃(最好的情况,易于发现)。

正如Gilles Gouaillardet所注意到的,不要使用mpif.h。相反,use mpi甚至更好use mpi_f08应该在新开发的程序中使用。