MPI_GATHERV 覆盖命令中未引用的数组
Posted
技术标签:
【中文标题】MPI_GATHERV 覆盖命令中未引用的数组【英文标题】:MPI_GATHERV overwrites arrays that are not referenced in command 【发布时间】:2019-07-29 07:56:07 【问题描述】:我有一个 MPI 的特殊问题,其中一个未在 MPI 命令中引用的数组被覆盖 --- 存在某种内存问题。
在gatherv 的第一种情况下,mpi 按预期工作。在第二次调用 gatherv 时,来自第一个数组的信息受到影响!
我正在使用的代码非常大,但是我创建了一个独立程序来大致显示问题。
但是,在较小的程序中,虽然仍然存在问题,但程序会调用 seg 错误,而不是像较大的程序那样继续运行。
program main
use mpi
integer :: chunksize, send_count, i_start, i_end
integer, allocatable :: rec_starts(:), rec_counts(:)
integer, parameter :: dp = 8; ! double precision
REAL(DP), allocatable:: array_2d(:,:)
REAL(DP), allocatable:: array_3d(:,:,:)
INTEGER, parameter:: num_skill=5, num_pref=2
INTEGER, parameter:: num_ed=3, num_children=2, num_age=4, num_market=28, num_health=2, num_year=2
INTEGER, parameter:: num_total_state_m=num_children*num_market*num_year*num_ed*num_age*num_health*num_ed*num_age*num_health
real(dp), dimension(num_skill,num_total_state_m) :: array_2d_local
real(dp), dimension(num_pref,num_pref,num_total_state_m) :: array_3d_local
integer i,j,k,l,m
!mpi vars
integer :: ierr, ntasks, mpi_id
! Set up MPI
call mpi_init(ierr)
call mpi_comm_size(mpi_comm_world, ntasks, ierr) !get number of tasks
call mpi_comm_rank(mpi_comm_world, mpi_id, ierr) !get id of each task
write(*,*) 'process ', mpi_id+1, 'of ', ntasks, 'is alive,', ' mpi_id:',mpi_id
!calculate which 'i' this thread is responsible for
chunksize = (num_total_state_m + ntasks - 1) / ntasks !note int/int rounds down
i_start = (mpi_id)*chunksize + 1
i_end = min((mpi_id+1)*chunksize,num_total_state_m)
!set up practice matrices
allocate(array_2d(num_skill,num_total_state_m), &
array_3d(num_pref,num_pref,num_total_state_m))
l = 1
m = -1
do i=1,num_skill
do j=1, num_total_state_m
if (mpi_id==0) array_2d_local(i,j) = l
if (mpi_id==1) array_2d_local(i,j) = m
l = l + 1
m = m - 1
end do
end do
l = 1
m = -1
do i=1, num_pref
do j=1, num_pref
do k=1, num_total_state_m
if (mpi_id==0) array_3d_local(i,j,k) = l
if (mpi_id==1) array_3d_local(i,j,k) = m
l = l + 1
m = m - 1
end do
end do
end do
! Next send matricies
allocate(rec_starts(ntasks), rec_counts(ntasks))
do i=1, ntasks
rec_counts(i) = min(num_total_state_m, i * chunksize) - (i-1)*chunksize
rec_starts(i) = (i-1) * chunksize
end do
rec_counts = rec_counts * num_skill
rec_starts = rec_starts * num_skill
send_count = rec_counts(mpi_id+1)
! -m (dimensions:num_skill, num_total_state_m) double
call mpi_gatherv(array_2d_local(:,i_start:i_end), send_count, &
mpi_double_precision, &
array_2d, rec_counts, rec_starts, mpi_double_precision, &
0, mpi_comm_world, ierr)
! Next do 3d array
! IF THESE LINES ARE UNCOMMENTED, THE PROGRAM WORKS FINE!
!do i=1, ntasks
! rec_counts(i) = min(num_total_state_m, i * chunksize) - (i-1)*chunksize
! rec_starts(i) = (i-1) * chunksize
!end do
rec_counts = rec_counts * num_pref
rec_starts = rec_starts * num_pref
send_count = rec_counts(mpi_id+1)
! -array_3d (num_pref,num_pref,num_total_state_m)double
print*, array_2d(1,1), mpi_id, 'before'
call mpi_gatherv(array_3d_local(:,:,i_start:i_end), send_count, &
mpi_double_precision, &
array_3d, rec_counts, rec_starts, mpi_double_precision, &
0, mpi_comm_world, ierr)
print*, array_2d(1,1), mpi_id, 'after'
deallocate(rec_starts, rec_counts)
deallocate(array_2d, array_3d)
end program main
这个小程序的输出如下所示:
mpifort -fcheck=all -fbacktrace -g -Og -ffree-line-length-2048 main.f90 -o run_main
mpiexec -np 2 run_main 2>&1 | tee run_main.log
process 1 of 2 is alive, mpi_id: 0
process 2 of 2 is alive, mpi_id: 1
1.0000000000000000 0 before
0.0000000000000000 1 before
Program received signal SIGSEGV: Segmentation fault - invalid memory reference.
Backtrace for this error:
#0 0x101e87579
#1 0x101e86945
#2 0x7fff6a9ecb5c
在较大的程序中,程序没有段错误,打印输出看起来像这样
1.0000000000000000 0 before
0.0000000000000000 1 before
-1.9018063100806379 0 after
0.0000000000000000 1 after
我一直在查看其他 SO 帖子: MPI_Recv overwrites parts of memory it should not access MPI_Recv overwrites parts of memory it should not access
但是,作为一个非 fortran/mpi 专家,不幸的是,这些帖子的回复不足以让我理解这个问题。
非常感谢任何帮助或见解。谢谢!
编辑:谢谢,只是我是个白痴。如果其他人遇到此问题,请三重检查您的 recvcounts
和 displs
!
【问题讨论】:
请向我们展示您的完整程序,或者至少是一个显示您遇到的问题的最小示例。特别是在这里,如果没有看到如何分配各种数组,就不可能回答您的问题,但更一般地说,如果没有完整的程序,在发布之前测试想法可能非常困难和耗时 - 因此这些想法永远不会被发布...... 我现在会试着把它放在一起,谢谢。我认为这是 rec_starts 的指针问题,第二次使用它时它指向以前的内存。更完整的代码应该会让这个更清晰,更容易修复你是对的。 嗨,我已经用一个独立的例子更新了这篇文章。我还想出了一个“修复”,但我仍然想了解这是一个已知问题还是交易是什么,所以在其他情况下我不会陷入这个错误,我可能不知道这个错误 【参考方案1】:您的初始代码可以
do i=1, ntasks
rec_counts(i) = min(num_total_state_m, i * chunksize) - (i-1)*chunksize
rec_starts(i) = (i-1) * chunksize
end do
rec_counts = rec_counts * num_skill
rec_starts = rec_starts * num_skill
send_count = rec_counts(mpi_id+1)
然后
rec_counts = rec_counts * num_pref
rec_starts = rec_starts * num_pref
send_count = rec_counts(mpi_id+1)
你只是忘了除以num_skill
。
一个简单的解决方法是将最后三行替换为
rec_counts = rec_counts * num_pref / num_skill
rec_starts = rec_starts * num_pref / num_skill
send_count = rec_counts(mpi_id+1)
如果您怀疑 MPI 库中存在错误,一个好的做法是尝试其他错误(例如 MPICH(派生)和 Open MPI)。如果您的应用程序同时崩溃,那么很可能是您的应用程序中存在错误。
【讨论】:
以上是关于MPI_GATHERV 覆盖命令中未引用的数组的主要内容,如果未能解决你的问题,请参考以下文章
使用 mpi_f08 模块时调用 mpi_gatherv 后数组的 Lbound 发生变化
MPI_GATHERV (Fortran) 从二维子矩阵创建一个新的二维矩阵