【问题标题】:What is exactly the count argument in MPI receiving functions?MPI 接收函数中的 count 参数到底是什么?
【发布时间】:2021-12-22 11:20:03
【问题描述】:

本题是关于接收操作的输入参数count的解释。

在 MPI 手册的one part 中它说(see here 我的):

int MPI_Recv(void *buf, int count, MPI_Datatype datatype, int source, int tag,
             MPI_Comm comm, MPI_Status *status)

Output Parameters

count
    maximum number of elements in receive buffer (integer)  <-------- see here

other part 中说

int MPI_Sendrecv(const void *sendbuf, int sendcount, MPI_Datatype sendtype,
                 int dest, int sendtag,
                 void *recvbuf, int recvcount, MPI_Datatype recvtype,
                 int source, int recvtag, MPI_Comm comm, MPI_Status * status)
...
recvcount
    number of elements in receive buffer (integer)   <-------- see here

长期以来,我忽略了措辞上的差异,并将它们解释为两种说法,即可以接收的最大元素数。

但是,如果我从字面上阅读recvcount(第二种情况)是缓冲区中可用(分配)的元素数量,不一定是可以接收的元素的最大数量。 换句话说,recvcount 的意思可能是 MPI 实现可以用来存储临时数据的元素数量,例如,其中的一部分最终会出现垃圾。

还有另一种情况会有所不同:如果我不确切知道收到的元素数量是多少,我可以将MAX_INT 作为参数传递,以确保程序逻辑的正确性。 但是当然,MAX_INT 不是接收缓冲区中分配的内存,它原则上只是说我可以接收其他人正在发送的任意数量的元素。

count(Recv)和recvcount(SendRecv)的解释真的有区别吗?

是否允许在任何一种情况下或两种情况下都传递MAX_INT如果接收元素的数量未知(在程序的一部分本地)

我对 OpenMPI 进行了一些试验,答案似乎是允许传递 MAX_INT 并按预期工作,但我不知道这是否是流行的解释。

(相反的解释(计数只是分配的内存)会很遗憾,因为这意味着只有分配的缓冲区及其大小才能有效地传递给这些函数。)


编辑:

明确地说,我要问的是在这个程序中,原则上正确且定义明确以接收整个发送的消息:

#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv) {
  MPI_Init(&argc, &argv);
 
  int count = 10;
  double xsend[count]; 
  double xrecv[123];

  for (int i=0; i<count; i++) {xsend[i] = (double)i;}

  int rank, nprocs;
  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
  MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
  assert (nprocs == 2);

  if(rank == 0) {MPI_Send(xsend, count, MPI_DOUBLE, 1, 0, MPI_COMM_WORLD);}

  if(rank == 1) {
     MPI_Recv(xrecv, NN, MPI_DOUBLE, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
     assert( xrecv[9] == 9 );
  }

  MPI_Finalize();
  return 0;
}

NN 的哪些值在语义上正确以接收整个消息:

  1. NN = 10
  2. NN = 20
  3. NN = 123
  4. NN = 100000
  5. NN = MAX_INT - 2
  6. NN = MAX_INT - 1
  7. NN = MAX_INT

我知道选项 1. 是推荐的,选项 2. 和 3. 肯定是正确的。 我的问题是其他选项是否定义明确。

【问题讨论】:

  • MPICH 文档不是 MPI 标准。请使用mpi-forum.org/docs/mpi-4.0/mpi40-report.pdf。我知道 MPICH 文档通常是标准的逐字副本,但最好不要将两者混为一谈。
  • @JeffHammond 是的。为了完整起见,第 37 页的链接文档中写着“计数,接收缓冲区的大小”。

标签: c mpi


【解决方案1】:

在接收缓冲区的情况下count是接收缓冲区的大小,以指定的类型表示,这是可以接收的消息大小的上限。 (请注意,对于发送缓冲区,计数当然是消息的确切大小。)短语“最大元素数”可能指的是这种上限行为。

但是,它令人困惑,我注意到在最新的标准 4.0 中没有使用它。 https://www.mpich.org/static/docs/v4.0a1/www3/MPI_Recv.html

所以:1. 您可以将大于您将收到的任何消息大小的计数传递到该缓冲区(在这种情况下,请在状态对象上调用 MPI_Get_count),但是 2. 正确报告您的错误'最好指定缓冲区的实际大小,否则可能会导致内存损坏。

从您提供的选项中编辑,选项 1、2 和 3 是正确的:它们是 1. 至少是消息的大小 2. 最多是缓冲区的大小。

【讨论】:

  • 感谢您的澄清。但真正的问题是,我可以传递大于缓冲区可用内存的计数吗?
  • 新的措辞是“接收缓冲区中的元素数”,这听起来更具限制性,因为这意味着我不能通过MAX_INT(或大计数的等价物),因为它不是大小任何缓冲区。是的,对于调试来说最好传递实际(预期)接收大小,但是我会声称在某些情况下它不知道该值,正确性是由程序的逻辑确保的,因为需要传递一些东西@987654325 @ 似乎是候选人(除了措辞似乎暗示相反)。最终通过MAX_INT 有多常见?
  • @alfC 是的,您可以传递大于缓冲区的计数,但这样做并不明智。 (甚至可能是未定义的行为。)您说“我不能通过 MAX_INT [...],因为它不是任何缓冲区的大小”,我从中得出结论,您没有得到缓冲区和消息之间的区别。您可以传递比预期消息大的缓冲区,但您应该使用准确给出缓冲区大小的count。同样,这不一定是消息的大小。
  • 这些选项都无效,因为MPI_Send() 可能会阻塞,直到发布匹配的接收。
  • @alfC 我用了两次“精确大小”这个短语。请仔细阅读我的话,因为我说得很明确。在第一种情况下,我说的是接收缓冲区,在第二种情况下,我说的是消息。在您修改后的代码中,分别是 123 和 10。 “您的回答中不清楚的地方”是的。您不应指定大于缓冲区大小的数字。 “在 SendRecv 的情况下,没有 MPI_Get_count” 错误。 Sendrecv 输出一个状态对象,你可以得到它的计数,就像你可以得到一个 Recv 调用的状态计数一样。
猜你喜欢
  • 2019-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-04
  • 2021-12-19
  • 1970-01-01
  • 2019-06-23
  • 1970-01-01
相关资源
最近更新 更多