用于复杂对象的MPI共享内存
MPI Shared Memory for Complex Object
我有一个大规模的代码,它在许多CPU核心上运行,可能跨越许多计算节点。该代码使用C++编写,并使用OpenMPI进行了并行处理。
我的代码有一个非常大的对象(大约10GB的RAM使用量),每个MPI进程都从中读取。这个对象偶尔会更新(可以通过一个进程完成,只需读取一个数据文件)。
到目前为止,我所做的是为每个MPI进程提供一个该对象的副本;但这意味着我的RAM严重受限,无法使用节点的全部CPU功率。因此,我一直在阅读MPI3规范中关于共享内存的内容。
我的问题是:在MPI进程之间共享复杂对象的最佳方式是什么?在我发现的所有例子中,MPI共享内存窗口都是创建的,用于交换简单的数据结构(浮点、int数组等)。我的全局对象是一个自定义类类型,包括许多成员变量,其中一些是指针,许多是其他复杂的类类型。因此,我觉得我不能只调用MPI_Win_allocate_shared
并传递复杂对象的地址,尤其是因为我想共享关于成员变量的所有信息(特别是,我想共享指针类型成员变量的底层值,即在MPI进程之间共享"深度副本",每个进程中的所有虚拟内存地址都是正确的)。
有可能用MPI共享内存实现这种"深度共享"吗?如果有,是否有这样做的"最佳实践"?或者另一个库(例如boost interprocess)会让这对我来说更可行/更简单吗?
附言:如果我不能找到一个好的解决方案,我将采用MPI+Ppthreads混合方法,在这种方法中,我知道我可以很容易地在每个具有pthreads的节点上拥有这个全局对象。但我真的希望找到一个优雅的MPI专用解决方案。
如果您跨越机器边界(并且在许多机器上使用节点),那么没有任何简单的方法可以实现您的目标。如果你只使用Windows或Linux机器(而不是混合使用它们),你可以尝试破解它,例如将一些共享资源附加到虚拟内存(使用系统API以高效的方式实现)。另一种方法是为大型对象创建自定义序列化/反序列化代码,然后将其作为二进制数组存储在内存中(在同一台机器上的进程之间共享)。如果您试图只存储"内存转储",那么问题是大小端序。如果您使用专用的MPIapi,那么所有的endian(和数据表示问题)都会得到适当的支持。目前我不确定PVM是否更好地支持这种场景,但在MPI的情况下,我可以从在同一台机器上直接使用VM开始(仅在进程之间共享一些访问密钥)。。。
附加答案1:
在一台机器上,我认为它应该很简单(你可能使用Windows,所以我现在将专注于这个平台)。在这种情况下,Endian问题和数据对齐并不重要,因为我假设您使用相同的选项编译所有的东西(并在相同的硬件上使用)。实现目标的最简单方法是将一个命名正确的文件映射到虚拟内存(在为不同对象创建许多映射之前,名称目前并不重要——在这种情况下,您需要一些命名模式来保持一致性)。例如,样品就在这里。
在创建虚拟内存之后,将所有对象数据放置在那里(使用老式的memcpy或所谓的放置构造函数)。当所有数据都已在虚拟内存中可用时,只需将带有一些附加属性的文件名发送到同一机器上的所有进程/节点即可。在虚拟内存空间的开头,如果有多个对象,您可以放置一些带有指向对象的指针的数组(例如,带有分配地址delta),以便轻松链接所有相关对象(在这种情况下,vm中的第一个On元素应该包含该数组中的elem数,这只是一个想法)。您可以在每个进程上将虚拟内存映射到相同的虚拟地址,这样,如果您对指针根本不感兴趣,就不必管理指针:)在这种情况下,不需要任何带有指针的数组!
使用虚拟内存的另一个好处是它优化了内存页面的使用,因此在您有如此大的数据对象的情况下,它不会吞噬10GB的内存。
顺便说一句:Windows支持与一些打开部分直接共享内存页。在CPP中,您有这样的支持。
- 使用Boost Interprocess创建托管共享内存需要很长时间
- 字符串共享内存映射的向量
- CUDA 使用共享内存平铺 3D 卷积实现
- 共享内存:MapViewOfFile 返回错误 5
- 如何在多写入器情况下对文件支持的共享内存中的大页面出错
- 有没有办法列出所有共享内存对象的名称?
- 共享内存的升压容器是否实现锁定?
- 共享内存中的健壮互斥锁不是那么健壮
- 使用IPC/共享内存将Integer数组从C++传递到Python
- 共享内存和性能
- 在这种特殊情况下,我是否需要在共享内存中使用原子类型
- 是否可以在专用内存空间中分配一个为提升管理共享内存而创建的对象
- fork(),在C中共享内存和指针
- 访问共享内存而不使用易失性、std::atomic、信号量、互斥锁和自旋锁
- 提升进程间共享内存open_or_create每次都会引发异常
- 通过 mmap-ed 共享内存传递可变长度 C 字符串
- 越界访问 CUDA 共享内存
- 在共享内存中插入映射映射时出现编译器错误
- 矩阵矢量产品 CUDA 通过平铺和共享内存提高性能
- 如何更改在 c++ 中使用提升库创建的共享内存的路径