我想通过 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
分割仅针对root
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)
您的代码中有两个问题。
首先,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
,这是段落末端的一个元素。一些编译器可以选择启用运行时间外部访问检查。例如,使用Intel Fortran,选项是-check bounds
。对于Gfortran,该选项是-fcheck=bounds
。访问阵列超越它们的末端可能会覆盖,从而改变其他阵列(最坏的情况,难以发现)或破坏堆指针并崩溃您的程序(最好的情况,易于发现)。
正如Gilles Gouaillardet所注意到的那样,请勿使用mpif.h
。相反,use mpi
甚至更好的use mpi_f08
应在新开发的程序中使用。