复杂对象的 MPI 共享内存
MPI Shared Memory for Complex Object
我有一个在许多 CPU 核心上运行的大规模代码,可能跨越多个计算节点。代码使用 C++ 并与 OpenMPI 并行化。
我的代码有一个非常大的对象(~10GB RAM 使用量),每个 MPI 进程都从中读取该对象。这个对象偶尔会更新(并且可以由单个进程完成,只需读取数据文件)。
到目前为止,我一直在为每个 MPI 进程提供该对象的副本;但这意味着我的 RAM 严重受限,无法使用节点的全部 CPU 功能。所以,我一直在阅读 MPI 3 规范中有关共享内存的内容。
我的问题是:跨 MPI 进程共享复杂对象的最佳方式是什么?在我找到的所有示例中,都创建了 MPI 共享内存 windows 并用于交换简单的数据结构(浮点数、整数数组等)。我的全局对象是一个自定义的class类型,包含了一些成员变量,其中一些是指针,还有很多是其他复杂的class类型。因此,我觉得我不能只调用 MPI_Win_allocate_shared
并传入我的复杂对象的地址,特别是因为我想共享有关成员变量的所有信息(特别是,我想共享指针类型成员变量的基础值 - 即跨 MPI 进程共享 "deep copy",每个进程中的所有虚拟内存地址都是正确的)。
是否可以通过 MPI 共享内存实现此 "deep sharing",如果可以,是否有 "best practice" 来实现?或者另一个库(例如 boost interprocess)会让我更 feasible/straightforward 吗?
P.S。如果我找不到好的解决方案,我将求助于混合 MPI+pthreads 方法,我知道我可以在每个节点上使用 pthreads 轻松地拥有这个全局对象。但我真的希望找到一个优雅的 MPI-only 解决方案。
如果您跨越机器边界(并且您在许多机器上使用节点),则没有任何简单的方法可以实现您的目标。
如果您只使用 Windows 或 Linux 机器(不混合使用),您可以尝试破解它,例如将一些共享资源附加到虚拟内存(使用系统 API 来提高效率方法)。其他方法可能是为您的大对象创建自定义 serialization/deserialization 代码,而不是将其作为二进制数组存储在内存中(以便在同一台机器上的进程之间共享它)。问题是 big/little 字节序,以防您尝试仅存储 "memory dump"。如果您使用专用 MPI api,则可以肯定地正确支持所有字节序(和数据表示问题)。
我现在不确定 PVM 是否更好地支持这种情况,但是如果是 MPI,我可以从在同一台机器上直接使用 VM 开始(仅在进程之间共享一些访问密钥)...
附加答案1:
我认为在一台机器上它应该很简单(你可能使用 Windows 所以我现在将专注于这个平台)。 Endian 问题和数据对齐在这种情况下并不重要,因为我假设您使用相同的选项编译所有内容(并在相同的硬件上使用)。实现目标的最简单方法是将一个正确命名的文件映射到虚拟内存(目前名称并不重要,直到您为不同的对象创建许多映射 - 在这种情况下您需要一些命名模式以保持一致性)。 Sample is here for instance.
创建虚拟内存后,将所有对象数据放在那里(使用旧式 memcpy 或所谓的放置构造函数)。当所有数据都已在虚拟内存中可用时,只需将带有一些附加属性的文件名发送到同一台机器上的所有 processes/nodes。在虚拟内存的开头 space 你可以放置一些带有对象指针的数组(例如分配地址增量),以便在你有多个对象时轻松链接所有相关对象(在这种情况下是第一个vm 中的 on 元素应该包含此类数组中的元素数量——这只是一些想法而已)。您可以将您的虚拟内存映射到每个进程的相同虚拟地址,这样如果您对它根本不感兴趣就不必管理指针:) 在这种情况下不需要任何带指针的数组!
使用虚拟内存的额外好处是它优化了内存页的使用,因此如果您有如此大的数据对象,它不会占用 10GB 的内存。
顺便说一句:Windows 支持与某些 switch on sections. In CPP you have such support 共享直接内存页。
我有一个在许多 CPU 核心上运行的大规模代码,可能跨越多个计算节点。代码使用 C++ 并与 OpenMPI 并行化。
我的代码有一个非常大的对象(~10GB RAM 使用量),每个 MPI 进程都从中读取该对象。这个对象偶尔会更新(并且可以由单个进程完成,只需读取数据文件)。
到目前为止,我一直在为每个 MPI 进程提供该对象的副本;但这意味着我的 RAM 严重受限,无法使用节点的全部 CPU 功能。所以,我一直在阅读 MPI 3 规范中有关共享内存的内容。
我的问题是:跨 MPI 进程共享复杂对象的最佳方式是什么?在我找到的所有示例中,都创建了 MPI 共享内存 windows 并用于交换简单的数据结构(浮点数、整数数组等)。我的全局对象是一个自定义的class类型,包含了一些成员变量,其中一些是指针,还有很多是其他复杂的class类型。因此,我觉得我不能只调用 MPI_Win_allocate_shared
并传入我的复杂对象的地址,特别是因为我想共享有关成员变量的所有信息(特别是,我想共享指针类型成员变量的基础值 - 即跨 MPI 进程共享 "deep copy",每个进程中的所有虚拟内存地址都是正确的)。
是否可以通过 MPI 共享内存实现此 "deep sharing",如果可以,是否有 "best practice" 来实现?或者另一个库(例如 boost interprocess)会让我更 feasible/straightforward 吗?
P.S。如果我找不到好的解决方案,我将求助于混合 MPI+pthreads 方法,我知道我可以在每个节点上使用 pthreads 轻松地拥有这个全局对象。但我真的希望找到一个优雅的 MPI-only 解决方案。
如果您跨越机器边界(并且您在许多机器上使用节点),则没有任何简单的方法可以实现您的目标。 如果您只使用 Windows 或 Linux 机器(不混合使用),您可以尝试破解它,例如将一些共享资源附加到虚拟内存(使用系统 API 来提高效率方法)。其他方法可能是为您的大对象创建自定义 serialization/deserialization 代码,而不是将其作为二进制数组存储在内存中(以便在同一台机器上的进程之间共享它)。问题是 big/little 字节序,以防您尝试仅存储 "memory dump"。如果您使用专用 MPI api,则可以肯定地正确支持所有字节序(和数据表示问题)。 我现在不确定 PVM 是否更好地支持这种情况,但是如果是 MPI,我可以从在同一台机器上直接使用 VM 开始(仅在进程之间共享一些访问密钥)...
附加答案1:
我认为在一台机器上它应该很简单(你可能使用 Windows 所以我现在将专注于这个平台)。 Endian 问题和数据对齐在这种情况下并不重要,因为我假设您使用相同的选项编译所有内容(并在相同的硬件上使用)。实现目标的最简单方法是将一个正确命名的文件映射到虚拟内存(目前名称并不重要,直到您为不同的对象创建许多映射 - 在这种情况下您需要一些命名模式以保持一致性)。 Sample is here for instance.
创建虚拟内存后,将所有对象数据放在那里(使用旧式 memcpy 或所谓的放置构造函数)。当所有数据都已在虚拟内存中可用时,只需将带有一些附加属性的文件名发送到同一台机器上的所有 processes/nodes。在虚拟内存的开头 space 你可以放置一些带有对象指针的数组(例如分配地址增量),以便在你有多个对象时轻松链接所有相关对象(在这种情况下是第一个vm 中的 on 元素应该包含此类数组中的元素数量——这只是一些想法而已)。您可以将您的虚拟内存映射到每个进程的相同虚拟地址,这样如果您对它根本不感兴趣就不必管理指针:) 在这种情况下不需要任何带指针的数组!
使用虚拟内存的额外好处是它优化了内存页的使用,因此如果您有如此大的数据对象,它不会占用 10GB 的内存。
顺便说一句:Windows 支持与某些 switch on sections. In CPP you have such support 共享直接内存页。