2016-06-09 82 views
1

我有一个可在多个计算节点上运行的大规模代码,可运行在许多CPU内核上。代码使用C++并与OpenMPI并行。用于复杂对象的MPI共享内存

我的代码有一个非常大的对象(〜10GB内存使用量),它是由每个MPI进程读取的。该对象偶尔会更新(可以通过单个进程完成,只需读取数据文件即可)。

我到目前为止一直在做的是给每个MPI过程一个这个对象的副本;但这意味着我受到严格的RAM限制,无法使用节点的全部CPU功能。所以,我一直在阅读有关MPI 3规范中的共享内存。

我的问题是:跨MPI流程共享复杂对象的最佳方式是什么?在我发现的所有例子中,创建了MPI共享内存窗口并用于交换简单的数据结构(浮点数,整数数组等等)。我的全局对象是一个自定义类类型,它包含许多成员变量,其中一些是指针,其中许多是其他复杂的类类型。因此,我觉得我不能只调用MPI_Win_allocate_shared并传递我复杂对象的地址,特别是因为我想分享有关成员变量的所有信息(特别是,我想分享基础值指针类型成员变量 - 即在MPI进程之间共享“深度拷贝”,每个进程中所有虚拟内存地址都是正确的)。

是否有可能通过MPI共享内存实现这种“深度共享”,如果有,是否有这样做的“最佳实践”?或者,另一个库(例如boost进程)是否使这对我更加可行/直接?

P.S.如果我找不到一个好的解决方案,我会采用混合MPI + pthreads方法,我知道我可以在每个节点上用pthreads轻松地创建这个全局对象。但我真的希望找到一个优雅的MPI专用解决方案。

+0

指向一个进程的虚拟地址空间的指针在其他进程中没有意义,除非共享内存映射到完全相同的基址。你想要的并不是不可能实现的:它可以归结为在所有进程的所有内存空间中找到一个足够大的空洞,并且使用首选地址调用mmap(),但既不可移植也不保证每个每次。正确的解决方案是使用相对指针并在取消引用前将基地址添加到每个指针的值。 –

+0

请注意,当底层通信器的进程组跨越多个共享内存节点时,无法使用'MPI_Win_allocate_shared'。在这种情况下,应该使用通常的MPI RMA。 –

+0

我的计划是像你说的那样使用RMA为每个节点获取一个对象的副本,然后在每个节点上使用共享内存,因此每个节点只有一个对象的副本(这足以保留我的内存使用量最小 - 只需要避免在1个节点上有n个副本。)另外,我正在寻找一个有保证的可移植解决方案(该代码需要可靠工作,并且理想情况下也应该在Linux和Windows上运行)。当你说“正确的解决方案是...”时,你能否更详细地解释这种技术如何解决我的问题?任何伪/示例代码也会有所帮助。谢谢! – davewy

回答

1

如果您跨越机器边界(并且您在许多机器上使用节点),没有任何简单的方法可以实现您的目标。 如果您仅使用Windows或Linux计算机(而不是混合它们),您可以尝试将其作为例如将某些共享资源附加到虚拟内存的方式进行破解(使用系统API以有效的方式执行此操作)。其他方法可以是为大对象创建自定义序列化/反序列化代码,并将其作为二进制数组存储在内存中(以在同一台计算机上的进程之间共享)。如果您尝试存储“内存转储”,则问题是大/小端。如果您使用专用的MPI API,则所有的endian(和数据显示问题)都可以得到适当的支持。 目前我不确定PVM是否更好地支持这种情况,但在MPI的情况下,我可以在同一台机器上直接使用虚拟机(仅在进程间共享一些访问密钥)...

其他回答1:

在一台机器上,它应该很简单,我认为(您可能使用Windows,所以我现在将专注于此平台)。在这种情况下,Endian问题和数据对齐无关紧要,因为我假定您使用相同的选项编译所有内容(并在相同的硬件上使用)。实现你的目标最简单的方法是映射到虚拟内存一个正确命名的文件(名称现在无关紧要,直到你为不同的对象创建了许多映射 - 在这种情况下,你需要一些命名模式的一致性)。 Sample is here for instance.

创建虚拟内存后,将所有对象数据放在那里(使用旧学校memcpy或只是所谓的放置构造函数)。如果虚拟内存中已有所有数据,则只需将文件名和一些附加属性发送到同一台计算机上的所有进程/节点即可。在虚拟内存空间的开始处,您可以放置​​一些指向对象的指针的数组(例如分配地址变化量),以便轻松链接所有相关对象(如果您有多个对象)(在这种情况下,vm中的第一个on元素应该包含这样的数组中的元素 - 这只是一个想法而已)。你可以将你的虚拟内存映射到每个进程的同一个虚拟地址,所以如果你根本不感兴趣的话,你不必管理指针:)在这种情况下,不需要任何带指针的数组!

使用虚拟内存的另外优点是它可以优化内存页的使用情况,所以如果您有这样的大数据对象,它不会吞下10GB的内存。

顺便说一句:Windows支持直接内存页面与部分switch共享。在CPP中,您有such support

+0

让我们假设为了简单起见,我只在一台机器上工作。 (对于多台机器,我会做类似上面提到的Hristo,使用RMA为每个节点获取一个对象的副本,然后使用共享内存在该节点上的所有特效之间共享该副本。)如果我只在一个节点上,你能否进一步解释你的二进制数组解决方案将如何工作?我如何获得全球地址并将数据存储在那里?我将如何将它转换成我想要的类型? – davewy

+0

我在“附加答案1”部分下添加了答案:) 希望很清楚我的想法是什么...... –