【发布时间】:2020-09-03 10:37:01
【问题描述】:
设置
我正在使用 mpi4py 在多个进程中按元素减少 numpy 数组。这个想法是 numpy 数组按元素求和,因此如果我有两个进程,并且每个进程都有数组:
Rank 0: [1, 1, 1]
Rank 1: [2, 3, 4]
减少后我应该有
[3, 4, 5]
这种情况下,使用这么短的数组,效果很好。
问题
但是,在我的实际用例中,这些数组非常长(在下面的示例代码中为array_length)。如果我发送长度小于或等于 505 个元素的 numpy 数组,我没有问题,但在此之上,我得到以下输出:
[83621b291fb8:01112] Read -1, expected 4048, errno = 1
而且我一直找不到任何记录在案的原因。然而,有趣的是,506*8 = 4048,假设有一些标头数据,这让我怀疑我在 mpi4py 或 MPI 本身的某个地方达到了 4kb 的缓冲区限制。
一种可能的解决方法
我已经设法解决了这个问题,方法是将我想要按元素减少的 numpy 数组分解为大小为 200 的块(只是小于 505 的任意数字),然后在每个块上调用 Reduce(),然后在主进程上重新组装。但是,这有点慢。
我的问题:
-
有谁知道这是否确实是由于 mpi4py/MPI 中的 4kb 缓冲区限制(或类似限制)?
-
有没有更好的解决方案,而不是像我目前正在做的那样将数组切片并多次调用 Reduce(),因为这似乎运行起来有点慢。
一些例子
下面是说明代码
- 问题和
- 一种可能的解决方案,基于将数组分割成更短的部分并执行大量 MPI Reduce() 调用,而不仅仅是一个(由
use_slices布尔值控制)
用case=0和use_slices=False可以看出错误(数组长度506)
使用case=1 和use_slices=False,错误消失(数组长度为505)
使用use_slices=True,无论case如何,即使case设置为一个非常长的数组(case=2),错误都会消失
示例代码
import mpi4py, mpi4py.MPI
import numpy as np
###### CASE FLAGS ########
# Whether or not to break the array into 200-element pieces
# before calling MPI Reduce()
use_slices = False
# The total length of the array to be reduced:
case = 0
if case == 0:
array_length= 506
elif case == 1:
array_length= 505
elif case == 2:
array_length= 1000000
comm = mpi4py.MPI.COMM_WORLD
rank = comm.Get_rank()
nprocs = comm.Get_size()
array_to_reduce = np.ones(array_length)*(rank+1) #just some different numbers per rank
reduced_array = np.zeros(array_length)
if not use_slices:
comm.Reduce(array_to_reduce,
reduced_array,
op = mpi4py.MPI.SUM,
root = 0)
if rank==0:
print(reduced_array)
else: # in this case, use_slices is True
array_slice_length = 200
sliced_array = np.array_split(array_to_reduce, range(200, array_length, 200))
reduced_array_using_slices = np.array([])
for array_slice in sliced_array:
returnedval = np.zeros(shape=array_slice.shape)
comm.Reduce(array_slice,
returnedval,
op = mpi4py.MPI.SUM,
root = 0)
reduced_array_using_slices=np.concatenate((reduced_array_using_slices, returnedval))
comm.Barrier()
if rank==0:
print(reduced_array_using_slices)
库版本
从源代码编译 -
openmpi 3.1.4
mpi4py 3.0.3
【问题讨论】:
-
如果您不在 Docker 容器中运行并且使用发行版提供的 Open MPI 会发生什么?检查您的路径和库目录,以确保您没有混淆不同的版本。
-
如果你
mpirun -mca btl vader,self...或mpirun -mca btl sm,self或mpirun -mca tcp,self怎么办? -
也许是因为你在一个容器中 :-)
mpirun -mca btl_vader_single_copy_mechanism none ...呢? -
默认情况下,
btl/vader使用基于process_vm_readv()和process_vm_writev()的单一复制机制,并且这些系统调用不允许在默认 docker 容器内。 -
Docker 的 default
seccompconfiguration 似乎将 Open MPI 使用的 CMA 调用限制为具有CAP_SYS_PTRACE功能的容器。尝试使用--add-cap=SYS_PTRACE启动容器,然后尝试不设置btl_vader_single_copy_mechanism。
标签: python docker mpi openmpi mpi4py