1

我设置了这个算法来在不同的处理器之间共享数据,到目前为止它一直有效,但我试图给它抛出一个更大的问题,我正在目睹一些非常奇怪的行为。我在 MPI_Isend 和 MPI_Recv 之间丢失了一些数据。

我在下面展示了一段代码。它基本上由三个阶段组成。首先,处理器将遍历给定数组中的所有元素。每个元素代表网格中的一个单元。处理器检查该元素是否正在其他处理器上使用。如果是,它使用单元的唯一全局 ID 作为标签向该进程进行非阻塞发送。如果否,则检查下一个元素,依此类推。

其次,处理器然后再次循环遍历所有元素,这一次检查处理器是否需要更新该单元格中的数据。如果是,那么数据已经被另一个进程发送出去了。当前进程只是进行阻塞接收,知道谁拥有数据和该单元的唯一全局 ID。

最后,MPI_Waital 用于在非阻塞发送期间存储在“req”数组中的请求代码。

我遇到的问题是整个过程完成了——代码没有挂起。但是某些单元接收的某些数据是不正确的。我通过在发送操作之前打印每条数据来检查发送的所有数据是否正确。请注意,我正在发送和接收数组的一部分。每次发送将传递 31 个元素。当我从接收它的进程打印数组时,31 个元素中有 3 个是垃圾。所有其他元素都是正确的。奇怪的是,垃圾总是相同的三个元素——第一个、第二个和最后一个元素。

我想排除我的算法中没有严重错误可以解释这一点。或者它可能与我正在处理的集群有关?正如我所提到的,这适用于我扔给它的所有其他模型,最多使用 31 个内核。当我尝试将 56 个内核用于解决问题时,我遇到了这种行为。如果没有出现任何错误,您能否建议一种方法来测试为什么某些发送部分没有到达目的地?

do i = 1, num_cells
   ! skip cells with data that isn't needed by other processors
   if (.not.needed(i)) cycle
   tag = gid(i) ! The unique ID of this cell in the entire system
   ghoster = ghosts(i) ! The processor that needs data from this cell
   call MPI_Isend(data(i,1:tot_levels),tot_levels,mpi_datatype,ghoster,tag,MPI_COMM,req(send),mpierr)
   send = send + 1
end do

sends = send-1

do i = 1, num_cells
   ! skip cells that don't need a data update
   if (.not.needed_here(i)) cycle
   tag = gid(i)
   owner = owner(i)
   call MPI_Recv(data(i,1:tot_levels),tot_levels,mpi_datatype,owner,tag,MPI_COMM,MPI_STATUS_IGNORE,mpierr)
end do

call MPI_Waitall(sends,req,MPI_STATUSES_IGNORE,mpierr)
4

2 回答 2

1

您的问题是您没有收到所有消息吗?请注意,仅仅因为 MPI_SEND 或 MPI_ISEND 完成,并不意味着相应的 MPI_RECV 已实际发布/完成。send 调用的返回仅意味着缓冲区可以被发送方重用。该数据可能仍会在发送方或接收方的内部某处进行缓冲。

如果您知道确实收到了消息很重要,则需要使用不同种类的发送,例如 MPI_SSEND 或 MPI_RSEND(或者如果您愿意,也可以使用非阻塞版本)。请注意,这实际上并不能解决您的问题。它可能只会让您更容易找出哪些消息没有显示。

于 2013-08-08T04:18:35.343 回答
0

我想出了一种让我的代码工作的方法,但我不完全确定为什么,所以我将在这里发布解决方案,也许有人可以评论为什么会这样,并可能提供更好的解决方案。

正如我在我的问题中所指出的以及我们在评论中所讨论的那样,似乎在发送/接收之间丢失了一些数据。缓冲区的概念对我来说是一个谜,但我认为可能没有足够的空间来容纳我的 Isend,让他们在收到之前就迷路了。所以我用 MPI_Bsend 调用交换了 MPI_Isend 调用。我弄清楚我的缓冲区需要使用 MPI_Pack_size 有多大。这样,我知道我将有足够的空间来接收我发送的所有消息。我使用 MPI_Buffer_attach 分配缓冲区大小。我摆脱了 MPI_Waitall,因为它不再需要,我用对 MPI_Buffer_detach 的调用替换它。

代码运行没有问题,并得到与串行案例相同的结果。我能够将问题规模扩大到我之前尝试过的规模,现在它可以工作了。因此,基于这些结果,我不得不假设由于缓冲区空间不足而丢失了一些消息。

我担心对代码性能的影响。我对不同的问题规模进行了缩放研究。见下图。x 轴给出了问题的大小(5 表示问题是 1 的 5 倍)。y 轴给出了完成程序执行的时间。显示了三行。串行运行程序显示为蓝色。size=1 的情况用绿线线性外推。我们看到代码执行时间与问题大小呈线性相关。红线显示并行运行程序——我们使用与问题大小相匹配的处理器数量(例如,2 个核心用于 size=2,4 个核心用于 size=4,等等)。

您可以看到并行执行时间随着问题大小的增加而非常缓慢地增加,这是预期的,除了最大的情况。我觉得最大情况下的性能不佳是由于消息缓冲量增加造成的,而在较小情况下则不需要。

在此处输入图像描述

于 2013-08-08T18:53:22.407 回答