21

我的 unix/windows C++ 应用程序已经使用 MPI 进行了并行化:作业在 N 个 cpus 中拆分,每个块并行执行,非常高效,速度扩展非常好,工作做得很好。

但是有些数据在每个过程中都是重复的,并且由于技术原因,这些数据不能轻易地通过 MPI 拆分(...)。例如:

  • 5 Gb 的静态数据,为每个进程加载完全相同的数据
  • 可以在 MPI 中分发的 4 Gb 数据,使用的 CPU 越多,每个 CPU 的 RAM 越小。

在 4 CPU 作业中,这意味着至少需要 20Gb RAM 负载,大部分内存“浪费”,这太糟糕了。

我正在考虑使用共享内存来减少整体负载,“静态”块每台计算机只会加载一次。

所以,主要问题是:

  • 是否有任何标准的 MPI 方法可以在节点上共享内存? 某种现成的+免费图书馆?

    • 如果没有,我将boost.interprocess使用 MPI 调用来分发本地共享内存标识符。
    • 共享内存将由每个节点上的“本地主机”读取,并且共享只读。不需要任何类型的信号量/同步,因为它不会改变。
  • 有任何性能下降或需要注意的特定问题吗?

    • (不会有任何“字符串”或过于奇怪的数据结构,一切都可以归结为数组和结构指针)
  • 该作业将在 PBS(或 SGE)排队系统中执行,在进程不干净退出的情况下,我想知道这些是否会清理节点特定的共享内存。

4

8 回答 8

9

高性能计算 (HPC) 中一种越来越普遍的方法是混合 MPI/OpenMP 程序。即你有 N 个 MPI 进程,每个 MPI 进程有 M 个线程。这种方法很好地映射到由共享内存多处理器节点组成的集群。

更改为这种分层并行化方案显然需要或多或少的侵入性更改,OTOH 如果做得好,除了减少复制数据的内存消耗外,它还可以提高代码的性能和可伸缩性。

根据 MPI 实现,您可能会或可能无法从所有线程进行 MPI 调用。这由您必须调用的 MPI_Init_Thread() 函数的required和参数指定,而不是 MPI_Init()。provided可能的值为

{ MPI_THREAD_SINGLE}
    只有一个线程会执行。
{ MPI_THREAD_FUNNELED}
    该进程可能是多线程的,但只有主线程会进行 MPI 调用(所有 MPI 调用都“汇集”到主线程)。
{ MPI_THREAD_SERIALIZED}
    该进程可能是多线程的,并且多个线程可以进行 MPI 调用,但一次只能调用一个:MPI 调用不是从两个不同的线程同时进行的(所有 MPI 调用都是“序列化的”)。
{ MPI_THREAD_MULTIPLE}
    多个线程可以调用 MPI,没有任何限制。

根据我的经验,像 Open MPI 这样的现代 MPI 实现支持最​​灵活的 MPI_THREAD_MULTIPLE。如果您使用较旧的 MPI 库或一些专门的架构,您的情况可能会更糟。

当然,您不需要使用 OpenMP 进行线程处理,这只是 HPC 中最流行的选项。您可以使用例如 Boost 线程库、英特尔 TBB 库或直接 pthread 或 windows 线程。

于 2010-01-06T00:52:54.163 回答
8

我没有使用过 MPI,但是如果它就像我见过的其他 IPC 库一样隐藏其他线程/进程/无论是在同一台机器上还是在不同机器上,那么它将无法保证共享内存。是的,它可以处理同一台机器上两个节点之间的共享内存,如果该机器自己提供共享内存的话。但是由于提出了复杂的一致性问题,尝试在不同机器上的节点之间共享内存充其量是非常困难的。我希望它只是未实现。

实际上,如果您需要在节点之间共享内存,最好的办法是在 MPI 之外进行。我认为您不需要使用boost.interprocess-style 共享内存,因为您没有描述不同节点对共享内存进行细粒度更改的情况;它是只读的或分区的。

John 和 deus 的答案涵盖了如何在文件中映射,这绝对是您想要对 5 Gb(千兆?)静态数据执行的操作。每个 CPU 的数据听起来是一样的,你只需要向每个节点发送一条消息,告诉它应该抓取文件的哪个部分。操作系统应该负责将虚拟内存映射到文件的物理内存。

至于清理...我认为它不会对共享内存进行任何清理,但是mmap应该清理 ed 文件,因为在清理进程时文件已关闭(这应该释放它们的内存映射)。我不知道有什么警告CreateFileMapping等。

当进程终止时,实际的“共享内存”(即boost.interprocess)不会被清理。如果可能的话,我建议尝试杀死一个进程并查看留下的内容。

于 2009-12-27T07:21:27.550 回答
2

使用 MPI-2,您可以通过 MPI_Put 和 MPI_Get 等函数获得 RMA(远程内存访问)。使用这些功能,如果您的 MPI 安装支持它们,肯定会帮助您减少程序的总内存消耗。成本增加了编码的复杂性,但这是并行编程乐趣的一部分。再说一次,它确实使您处于 MPI 领域。

于 2009-12-29T10:05:14.560 回答
1

MPI-3 提供了共享内存窗口(参见例如MPI_Win_allocate_shared()),它允许使用节点上的共享内存而无需任何额外的依赖。

于 2018-03-26T06:50:10.197 回答
0

如果将静态数据存储在文件中,则可以在 unix 上使用 mmap 来随机访问数据。当您需要访问数据的特定位时,数据将被分页。您需要做的就是在文件数据上覆盖任何二进制结构。这是上面提到的 CreateFileMapping 和 MapViewOfFile 的 unix 等价物。

顺便说一句,当调用 malloc 请求多于一页数据时,glibc 使用 mmap。

于 2009-12-26T22:50:34.310 回答
0

我对unix了解不多,也不知道MPI是什么。但在 Windows 中,您所描述的是文件映射对象的完全匹配。

如果此数据嵌入到您的 .EXE 或它加载的 .DLL 中,那么它将自动在所有进程之间共享。即使由于崩溃而拆除您的进程也不会导致任何泄漏或未释放的数据锁定。但是 9Gb .dll 听起来有点可疑。所以这可能对你不起作用。

但是,您可以将数据放入一个文件中,然后CreateFileMapping放在MapViewOfFile上面。映射可以是只读的,您可以将文件的全部或部分映射到内存中。所有进程将共享映射相同底层 CreateFileMapping 对象的页面。关闭取消映射视图并关闭句柄是一种很好的做法,但如果您不这样做,操作系统会在拆卸时为您执行此操作。

请注意,除非您运行的是 x64,否则您将无法将 5Gb 文件映射到单个视图(甚至是 2Gb 文件,1Gb 可能也可以)。但是鉴于您正在谈论它已经工作,我猜您已经只是 x64 了。

于 2009-12-26T21:27:09.563 回答
0

几年前我在使用 MPI 时遇到了这个问题。

我不确定 SGE 是否理解内存映射文件。如果您针对 beowulf 集群进行分发,我怀疑您将遇到一致性问题。你能谈谈你的多处理器架构吗?

我的草案方法是建立一个架构,其中数据的每个部分都由定义的 CPU 拥有。将有两个线程:一个线程是 MPI 双向谈话者,一个线程用于计算结果。请注意,MPI 和线程并不总是能很好地协同工作。

于 2010-01-06T01:15:56.650 回答
0

我在 SHUT 有一些使用 MPI 的项目。

据我所知,有很多方法可以使用 MPI 分配问题,也许您可​​以找到另一个不需要共享内存的解决方案,我的项目是求解7,000,000 方程和 7,000,000 变量

如果你能解释你的问题,我会尽力帮助你

于 2009-12-28T19:28:53.217 回答