0

我正在尝试在 openmp 线程中使用 MPI_Allgather 类型的功能。也就是说,所有线程将共同拥有一个数据副本(但每个线程只会生成其中的一部分)。

事实上,通过使用 MPI_SEND 和 MPI_RECV 的“tag”字段中的线程 ID,openmp 线程之间的通信是可能的。但是 MPI_Allgather 似乎不是这样工作的。

例子

我有 2 个 MPI 进程。每个进程有 2 个 openmp 线程。现在这 4 个线程中的每一个都计算部分数据。我想使用 MPI_Allgather 以便所有线程组合它们的数据并拥有组合数据的副本。但似乎 MPI_Allgather 仅适用于 MPI 进程的粒度。

我将不胜感激有关如何做到这一点的任何建议。

谢谢!

4

1 回答 1

1

所有 MPI 通信调用都针对称为rank的实体。目前所有 MPI 实现都遵循rank等于OS 进程的解释,即不共享内存空间的实体。原则上,您可以通过制作消息标签来解决单个线程是一种解决方法(或者更确切地说是一种 hack) - 例如,尝试在MPI_ANY_TAG没有无限循环和/或中央进程范围的调度机制的情况下实现多个线程的模拟。

在 MPI-3.0 的早期阶段有一个提议包括所谓的端点,这基本上是一种允许将一组等级分配给进程内的一组线程的机制。该提案未通过投票机制,文本需要进一步完善。

也就是说,在不使用 pt2pt 操作重新实现集体调用的情况下,以下是实现您想要的合理方法:

#pragma omp parallel shared(gbuf) private(buf,tid)
{
   tid = omp_get_thread_num();
   ...
   // Gather threads' data into the shared buffer 'gbuf'
   // Data should start at gbuf[rank * num_threads * data_per_thread]
   memcpy(gbuf + (rank*num_threads + tid)*data_per_thread,
          buf, data_per_thread*size);

   // Make sure all threads have finished copying their chunks
   // then gather the data from all the other ranks
   #pragma omp barrier
   #pragma omp single
   {
       MPI_Allgather(MPI_IN_PLACE, 0, MPI_TYPE_NULL,
                     gbuf, num_threads*data_per_thread, data_type, comm);
   }
   ...
}

它首先将每个线程的本地缓冲区中的数据收集buf到全局接收缓冲区gbuf中。在此示例中,使用的是简单memcpy的,但如果使用的是复杂的派生数据类型,则可能会更复杂。一旦正确收集了本地数据,就可以使用就地数据MPI_Allgather从其他进程中收集数据。该single构造确保每个进程只有一个线程会进行全集合调用。

如果所有进程的线程数不相同,MPI_Allgatherv则应改为使用。

于 2013-09-27T11:49:40.447 回答