2009-12-26 161 views
20

我的unix/windows C++应用程序已经使用MPI进行了并行化:作业被拆分为N cpus,并且每个块都并行执行,相当高效,非常好的速度调整,作业完成正确。共享内存,MPI和排队系统

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

  • 5静态数据,每个进程加载
  • 4 GB的数据,可以在MPI分布完全相同的东西的GB,所述多个CPU被使用,更小的这个每个CPU RAM是。

对于一个4 CPU的工作,这意味着至少20Gb的RAM负载,大部分内存'浪费',这是可怕的。

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

所以,主要的问题是:

  • 有什么标准MPI方式在一个节点上共享内存?某种现成的+免费图书馆?

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

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

+0

答案到目前为止,测试和进一步的读数,内存映射文件可能是最简单的选择: - 只有主MPI进程需要“准备”内存文件,这将被所有进程映射。 - 由于该文件将是只读的,因此不需要担心内容的一致性。 - 没有关于性能的想法寿命...也许只有实验才能说明。 – Blklight 2009-12-27 15:50:24

+0

性能完全取决于您的平台。你的细节很稀疏,但是考虑到你可用的CPU和RAM,你不应该有一个大问题。如果您需要更改共享内存(您的分布式数据),则不需要共享内存的内容是持久性的,只需要共享内存即可。在这种情况下,您的系统将浪费大量时间将所有内存更改写入磁盘。 – 2010-01-10 05:38:35

+0

已经离开,不能选择最后的答案,最多的一个得到它:) 但无论如何,很多好的答案四周,但没有什么回答我正在寻找的东西,所以我想没有广泛的标准的方式来做到这一点! – Blklight 2010-01-11 19:40:28

回答

9

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

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

根据MPI实现,您可能会也可能不会从所有线程进行MPI调用。这由MPI_Init_Thread()函数的参数requiredprovided指定,您必须调用该函数而不是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. 

以我的经验,现代MPI实现如Open MPI支持最灵活MPI_THREAD_MULTIPLE。如果您使用较旧的MPI库或某些专门的体系结构,则可能会变得更糟。

当然,您不需要使用OpenMP进行线程处理,这只是HPC中最受欢迎的选项。您可以使用例如Boost线程库,Intel TBB库或者直线pthread或windows线程。

+0

如果您将代码更改为每个共享内存多处理器节点上的多线程,请确保仔细编写线程调度,以将高速缓存局部性和其他内存体系结构考虑在内。 – stephan 2010-01-07 07:20:07

+2

我不确定混合方法越来越普遍。这里有一个证据表明,它可能不是一种值得采取的方法 - http://www.pdc.kth.se/education/historical/2008/PRACE-P2S2/coursework/handouts.html#hybrid 是的,这是一个很好的概念,但是与修改应用程序所需的努力相比,它在实践中存在可疑的价值。 – 2010-01-07 09:47:07

+0

此答案未解决问题 – lurscher 2012-01-17 21:47:25

0

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

如果这些数据嵌入在您加载的.EXE或.DLL文件中,那么它将自动在所有进程之间共享。即使崩溃导致您的流程被破坏,也不会导致数据泄露或未公布的锁定。然而一个9Gb .dll听起来有点不对劲。所以这可能不适合你。

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

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

+0

从文档中,我推断boost.interprocess允许以跨平台的方式(不需要#ifdef)和“干净的”代码来做到这一点。还有一个特定于Windows的选项,可以准确地描述你所描述的内容。 但是,这里问题的关键不在于共享内存系统的技术实现,而是如何在8核心机器上分布128个应用程序实例时干净利落地完成此操作:-) – Blklight 2009-12-26 22:17:46

+1

我不确定为什么那会是一个问题。你是说你想分享多个_machines_。我很确定每台机器只会看到它自己的内存,并且机器上的所有内核都共享该机器内存的视图。 – 2009-12-26 22:35:06

0

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

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

+0

glibc malloc mmap阈值默认为128 kB,与页面大小不同。 – janneb 2010-01-07 06:05:25

7

我没有使用MPI,但是如果它像其他IPC库一样,我已经看到隐藏其他线程/进程/不管是在相同或不同的机器上,那么它将无法保证共享记忆。是的,它可以处理同一台机器上两个节点之间的共享内存,如果该机器本身提供了共享内存的话。但由于复杂的一致性问题的出现,试图在不同机器上的节点之间共享内存将会非常困难。我希望它只是未被实现。

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

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

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

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

0

我在SHUT中有一些MPI项目。

我所知,有很多方法来分发问题使用MPI,也许你能找到不要求共享内存的另一个解决方案, 我的计划解决的7000000方程和7000000可变

如果你可以解释你的问题,我会尽力帮你

+0

当然,问题的“静态”部分可以更好地并行化,但开发时间会很长。 “完整”问题的大部分内存都可以在每个计算节点上加载*一次*。所以,我的目标是共享内存,并瞄准最好的技术来做到这一点! – Blklight 2009-12-29 02:56:33

+0

我想知道的是你解决的问题有7 * 10^6个变量。 – 2010-01-05 03:01:57

2

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

+0

这不会极大地增加访问共享内存的延迟吗?或者MPI_Get只是一个通过内存总线直接获取的别名? – Crashworks 2010-01-06 23:05:13

+0

@Crashworks是的,MPI-2 RMA实际上并没有比传统的Send/Recv更快。在很多情况下,由于需要注册内存窗口,速度较慢。原则上,在未来的特殊网络硬件支持下,它可能会变得更快,但今天没有理由使用它。 – janneb 2010-01-07 06:06:59

+0

是的。但是也许使用MPI2 RMA的一个理由是在MPI范例内进行共享内存编程,而不必求助于内存映射文件或IPC库等低级功能。较低的执行性能成本可能会大大降低开发性能。我想知道OP在做什么。 – 2010-01-08 09:17:27

0

几年前我用MPI的时候遇到过这个问题。

我不确定SGE是否理解内存映射文件。如果你正在分发一个beowulf集群,我怀疑你会遇到一致性问题。你能否谈谈你的多处理器体系结构?

我的草案方法是设置一个架构,其中数据的每个部分都由定义的CPU拥有。会有两个线程:一个线程是MPI双向通话器,另一个线程用于计算结果。请注意,MPI和线程并不总是一起玩。

+0

中的任何问题是,数据仅由一个CPU拥有,并且是只读的。这里没有一致性问题。所以,内存映射文件可能是一个简单的选择。 – Blklight 2010-01-08 05:01:23

+0

同意。但这将取决于你的架构。 memmapped文件在共享内存体系结构中最好。我不确定*你会怎么做,以及一个beowulf集群。 – 2010-01-08 16:46:00