我的unix / windows C ++应用程序已经使用MPI进行了并行化:作业被分割为N cpus,并且每个块都是并行执行,效率非常高,速度非常好,工作正确完成。
但是在每个过程中都会重复一些数据,并且由于技术原因,这些数据不能轻易地通过MPI分割(...)。 例如:
在一个4 CPU的工作中,这意味着至少有20Gb的RAM负载,大部分内存“浪费”,这很糟糕。
我在考虑使用共享内存来减少总体负载,每台计算机只会加载一次“静态”块。
所以,主要问题是:
是否有任何标准的MPI方式在节点上共享内存?某种现成的+免费库?
boost.interprocess
并使用MPI调用来分发本地共享内存标识符。是否有任何性能损失或特别需要注意的问题?
作业将在PBS(或SGE)排队系统中执行,如果进程不干净退出,我想知道这些是否会清理特定于节点的共享内存。
答案 0 :(得分:8)
高性能计算(HPC)中一种越来越常见的方法是混合MPI / OpenMP程序。即你有N个MPI进程,每个MPI进程有M个线程。此方法很好地映射到由共享内存多处理器节点组成的集群。
更改为这样的分层并行化方案显然需要一些或多或少的侵入性更改,如果正确完成OTOH,除了减少复制数据的内存消耗外,它还可以提高代码的性能和可伸缩性。
根据MPI实现,您可能会也可能无法从所有线程进行MPI调用。这由MPI_Init_Thread()函数的required
和provided
参数指定,您必须调用它而不是MPI_Init()。可能的值是
{ MPI_THREAD_SINGLE} Only one thread will execute. { MPI_THREAD_FUNNELED} The process may be multi-threaded, but only the main thread will make MPI calls (all MPI calls are ``funneled'' to the main thread). { MPI_THREAD_SERIALIZED} The process may be multi-threaded, and multiple threads may make MPI calls, but only one at a time: MPI calls are not made concurrently from two distinct threads (all MPI calls are ``serialized''). { MPI_THREAD_MULTIPLE} Multiple threads may call MPI, with no restrictions.
根据我的经验,像Open MPI这样的现代MPI实现支持最灵活的MPI_THREAD_MULTIPLE。如果您使用较旧的MPI库或某些专用架构,则可能会更糟糕。
当然,您不需要使用OpenMP进行线程化,这只是HPC中最受欢迎的选项。你可以用例如Boost线程库,英特尔TBB库,或直接pthreads或Windows线程。
答案 1 :(得分:7)
我没有使用MPI,但如果它像其他IPC库一样,我看到隐藏其他线程/进程/无论是在相同还是不同的机器上,那么它将无法保证共享内存。是的,如果该机器本身提供共享内存,它可以处理同一台机器上两个节点之间的共享内存。但是,由于提出了复杂的一致性问题,尝试在不同机器上的节点之间共享内存将是非常困难的。我希望它只是没有实现。
在所有实际情况中,如果您需要在节点之间共享内存,最好的办法是在MPI之外执行此操作。我认为您不需要使用boost.interprocess
样式的共享内存,因为您没有描述不同节点对共享内存进行细粒度更改的情况;它是只读的或分区的。
John和deus的答案涵盖了如何在文件中映射,这绝对是你想要为5 Gb(giga bit ?)静态数据做的。每个CPU的数据听起来都是一样的,你只需要向每个节点发送一条消息,告诉它应该抓取哪个文件部分。操作系统应该将虚拟内存映射到物理内存到文件。
至于清理......我认为它不会对共享内存进行任何清理,但是当一个进程关闭文件(应该释放它们的内存映射)时,应该清除mmap
个ed文件被清理干净了。我不知道CreateFileMapping
等有什么警告。
当进程终止时,不会清除实际的“共享内存”(即boost.interprocess
)。如果可能的话,我建议您尝试杀死一个进程并查看遗留的内容。
答案 2 :(得分:2)
使用MPI-2,您可以通过MPI_Put和MPI_Get等功能获得RMA(远程内存访问)。使用这些功能,如果您的MPI安装支持它们,肯定会帮助您减少程序的总内存消耗。成本增加了编码的复杂性,但这是并行编程乐趣的一部分。然后,它确实让你进入MPI领域。
答案 3 :(得分:0)
我对unix知之甚少,我不知道MPI是什么。但在Windows中,您所描述的内容与文件映射对象完全匹配。
如果此数据嵌入在您加载的.EXE或.DLL中,则它将自动在所有进程之间共享。即使由于崩溃,您的进程的拆除也不会导致任何泄漏或未发布的数据锁定。然而,一个9Gb .dll听起来有点不确定。所以这可能不适合你。
但是,您可以将数据放入文件中,然后在其上CreateFileMapping
和MapViewOfFile
。映射可以是只读的,您可以将全部或部分文件映射到内存中。所有进程将共享映射到相同底层CreateFileMapping对象的页面。关闭unmap视图和关闭句柄是一个好习惯,但是如果你不这样做,操作系统会在拆卸时为你完成。
请注意,除非您运行x64,否则您将无法将5Gb文件映射到单个视图(甚至是2Gb文件,1Gb可能会起作用)。但鉴于你说的已经有了这个,我猜你已经只有x64了。
答案 4 :(得分:0)
如果将静态数据存储在文件中,则可以在unix上使用mmap来随机访问数据。当您需要访问特定的数据位时,将分页数据。您需要做的就是覆盖文件数据上的任何二进制结构。这是上面提到的CreateFileMapping和MapViewOfFile的unix等价物。
顺便说一下,当一个人调用malloc来请求超过一页数据时,glibc会使用mmap。
答案 5 :(得分:0)
我在SHUT中有一些MPI项目。
据我所知,有很多方法可以使用MPI分发问题,也许你可以找到另一种不需要共享内存的解决方案, 我的项目正在解决一个 7,000,000个等式和7,000,000个变量
如果你能解释你的问题,我会尽力帮助你
答案 6 :(得分:0)
几年前,当我使用MPI时,我遇到了这个小问题。
我不确定SGE是否了解内存映射文件。如果你要分发beowulf群集,我怀疑你会遇到一致性问题。你能谈谈你的多处理器架构吗?
我的草案方法是建立一个架构,其中数据的每个部分都由定义的CPU拥有。将有两个线程:一个线程是MPI双向讲话者,一个线程用于计算结果。请注意,MPI和线程并不总能很好地协同工作。
答案 7 :(得分:0)
MPI-3提供共享内存窗口(参见例如MPI_Win_allocate_shared()
),它允许使用节点上的共享内存,而不需要任何其他依赖。