我想用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)
答案 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
应该在新开发的程序中使用。