gpt4 book ai didi

python - mpi4py Reduce() 中可能的缓冲区大小限制

转载 作者:行者123 更新时间:2023-12-02 17:59:49 25 4
gpt4 key购买 nike

设置
我正在使用 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 bool 值控制)

  • case=0use_slices=False ,可以看到错误(数组长度506)
    case=1use_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

    最佳答案

    这不是问题 mpi4py本身。该问题来自跨内存附加 (CMA) 系统调用 process_vm_readv()process_vm_writev() Open MPI 的共享内存 BTL(字节传输层,也就是在列之间移动字节的东西)用来加速运行在同一节点上的列之间的共享内存通信,避免将数据复制到共享节点和从共享节点复制两次数据。内存缓冲区。这种机制涉及一些设置开销,因此仅用于较大的消息,这就是为什么只有在消息大小超过 Eager 阈值后才会出现问题的原因。

    CMA 是 ptrace 的一部分内核服务系列。 Docker 使用 seccomp限制容器内运行的进程可以进行哪些系统调用。 default profile有以下内容:

        {
    "names": [
    "kcmp",
    "process_vm_readv",
    "process_vm_writev",
    "ptrace"
    ],
    "action": "SCMP_ACT_ALLOW",
    "args": [],
    "comment": "",
    "includes": {
    "caps": [
    "CAP_SYS_PTRACE"
    ]
    },
    "excludes": {}
    },

    限制 ptrace对具有 CAP_SYS_PTRACE 的容器的相关系统调用能力,这不属于默认授予的能力。因此,要使 Docker 中的 Open MPI 正常运行,需要通过调用 docker run 授予所需的能力。具有以下附加选项:
    --cap-add=SYS_PTRACE

    这将允许 Open MPI 正常运行,但启用 ptrace在某些容器部署中可能存在安全风险。因此,另一种方法是禁用 Open MPI 使用 CMA。这是通过根据 Open MPI 的版本和使用的共享内存 BTL 设置 MCA 参数来实现的:
  • sm BTL(Open MPI 1.8 之前的默认值):--mca btl_sm_use_cma 0
  • vader BTL(自 Open MPI 1.8 起默认):--mca btl_vader_single_copy_mechanism none

  • 禁用单拷贝机制将强制 BTL 通过共享内存缓冲区使用流水线拷贝,这可能会也可能不会影响 MPI 作业的运行时间。

    阅读 here关于共享内存 BTL 和 Open MPI 中的零(单?)复制机制。

    关于python - mpi4py Reduce() 中可能的缓冲区大小限制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61855885/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com