mpi4py 的 MPI 数据传输错误
Posted
技术标签:
【中文标题】mpi4py 的 MPI 数据传输错误【英文标题】:MPI data transfer errors with mpi4py 【发布时间】:2020-01-18 15:17:18 【问题描述】:我有一个集群,我被它和 mpi4py 困住了。我有一个相当复杂的代码,而 MPI 只是在传输数据时失败了。 为了让事情更清楚,我编写了一个简单的“hello world”代码,它只是在节点之间传输大型数组。 数组初始化为 0,然后填充来自另一个节点的数组。
import dill
from mpi4py import MPI
MPI.pickle.__init__(dill.dumps, dill.loads)
comm = MPI.COMM_WORLD
rank = comm.rank
import numpy as np
for k in range(5):
if rank == 0:
# node 0 sends hi to other nodes
for i in range(1, comm.size):
msg = np.ones(10000000, np.double)
comm.Send([msg, MPI.DOUBLE], dest=i, tag=0)
else:
# other nodes receive hi
msgin = np.zeros(10000000, np.double)
comm.Recv([msgin, MPI.DOUBLE], source=0, tag=0)
with open('solution1.txt', 'a') as f:
f.write(f'rank hi, msgin[:10] np.average(msgin)\n')
# and then send reply to 0 node
msgout = np.ones(10000000)
comm.Send([msgout, MPI.DOUBLE], dest=0, tag=1)
if rank == 0:
# node 0 receives replies
for i in range(1, comm.size):
msgin = np.zeros(10000000, np.double)
comm.Recv([msgin, MPI.DOUBLE], tag=1, source=i)
with open('solution1.txt', 'a') as f:
f.write(f'rank reply, msgin[:10] np.average(msgin)\n')
结果如下:
1 hi [1. 1. 1. 1. 1. 1. 1. 1. 1. 1.] 1.0
2 hi [1. 1. 1. 1. 1. 1. 1. 1. 1. 1.] 1.0
3 hi [1. 1. 1. 1. 1. 1. 1. 1. 1. 1.] 1.0
4 hi [1. 1. 1. 1. 1. 1. 1. 1. 1. 1.] 1.0
5 hi [1. 1. 1. 1. 1. 1. 1. 1. 1. 1.] 1.0
1 reply [1. 1. 1. 1. 1. 1. 0. 0. 0. 0.] 6e-08
2 reply [1. 1. 1. 1. 1. 1. 1. 1. 1. 1.] 1.0
3 reply [1. 1. 1. 1. 1. 1. 0. 0. 0. 0.] 6e-08
4 reply [1. 1. 1. 1. 1. 1. 0. 0. 0. 0.] 6e-08
5 reply [1. 1. 1. 1. 1. 1. 0. 0. 0. 0.] 6e-08
1 hi [1. 1. 1. 1. 1. 1. 1. 1. 1. 1.] 1.0
2 hi [1. 1. 1. 1. 1. 1. 1. 1. 1. 1.] 1.0
3 hi [1. 1. 1. 1. 1. 1. 1. 1. 1. 1.] 1.0
4 hi [1. 1. 1. 1. 1. 1. 1. 1. 1. 1.] 1.0
5 hi [1. 1. 1. 1. 1. 1. 1. 1. 1. 1.] 1.0
1 reply [1. 1. 1. 1. 1. 1. 0. 0. 0. 0.] 6e-08
2 reply [1. 1. 1. 1. 1. 1. 0. 0. 0. 0.] 6e-08
3 reply [1. 1. 1. 1. 1. 1. 0. 0. 0. 0.] 6e-08
4 reply [1. 1. 1. 1. 1. 1. 0. 0. 0. 0.] 6e-08
5 reply [1. 1. 1. 1. 1. 1. 0. 0. 0. 0.] 6e-08
1 hi [1. 1. 1. 1. 1. 1. 0. 0. 0. 0.] 6e-08
如您所见,有时只传输了 6 个双精度值,而不是 10000000。 此日志不完整 - 所有后续消息也只有 6 个值。 有趣的是,结果是可重现的:节点 2 总是首先回复正确的消息,而所有其他节点都回复不正确的消息。
代码在同一个集群的单个节点上完美运行。它还在谷歌云中完美运行(6 个节点,每个节点 32 个核心)。 我尝试了不同的技巧并得到了相同的结果:
将 Send/Recv 替换为 Isend/Irecv + Wait
将发送/接收与标准泡菜和莳萝泡菜一起使用。此代码在解码泡菜数据时失败。
试过 openmpi 2.1.1、4.0.1 和 intel mpi 库
尝试了英特尔的修复:
export I_MPI_SHM_LMT=shm
可能是网络设置有问题,但我真的不知道该尝试什么。
该设置是一个多节点集群,在 2-1 超额订阅胖树中具有 Mellanox 4x FDR Infiniband 互连。 24 个节点的集合有 12 个上行链路进入大型核心 Infiniband 交换机。每个节点具有 64 GiB 的 4 通道 2133 MHz DDR4 SDRAM(68 GB/秒)内存;两个 Intel Xeon E5-2670 v3 (Haswell) CPU。
【问题讨论】:
回复时,尝试将msgout = np.ones(10000000)
替换为msgout = np.ones(10000000, np.double)
谢谢,我已经更正了——但是 numpy 使用 np.double 作为默认值,所以结果是一样的。
【参考方案1】:
在我的设置中,我发现始终使用相同的缓冲区来接收结果很有用。
因此可以尝试在代码的早期声明一次msgin = np.zeros(10000000, np.double)
并一次又一次地使用它。每次收到消息时,您都可以执行msgin.fill(np.nan)
来“清除”缓冲区。
我不知道为什么它对我有用,但问题似乎消失了。
祝你好运!
【讨论】:
【参考方案2】:我在类似的集群环境中遇到了类似的问题。它仅出现在与 Infiniband 多节点通信相关的情况下,用于特定大小 (> 30MB) 的发送/接收缓冲区。我可以通过从 OpenMPI 3.x 降级到 OpenMPI 2.1.5 来解决问题(Mpi4py 版本似乎无关紧要)
相应的 C 代码运行良好(相同的集群、内核/节点数、相同的 OpenMPI 3.x 等)因此问题似乎在 mpi4py 和 OpenMPI 3 之间,但我无法调试。
【讨论】:
我还发现,当缓冲区大小很小(在我的情况下为 参数是 I_MPI_FABRICS=shm:tcp 在这两种情况下,传输速率都没有接近规格(大约 100Mb/s 与多个 GB/s)我无法进一步调试它,这是一个限制访问的竞争平台。比赛已经结束了,反正集群也要退役了。以上是关于mpi4py 的 MPI 数据传输错误的主要内容,如果未能解决你的问题,请参考以下文章