在总和上创建优化的归约

Posted

技术标签:

【中文标题】在总和上创建优化的归约【英文标题】:Creating an optimized reduce on sum 【发布时间】:2018-09-03 12:56:25 【问题描述】:

我刚刚开始学习 HPC 课程,并且正在做一项任务,我们希望在 MPI_SUM 上实现与 MPI_Reduce 等效的 Reduce 函数......够简单吧?这是我所做的:

我从将数据/数组从所有节点发送到根节点(排名第 0 的过程)的基本概念开始,然后计算总和。

作为第二步,我进一步优化了它,以便每个进程将数据发送到计算总和的镜像,并且这个过程不断重复,直到结果最终出现在根节点(第 0 个进程)中。我的实现如下:

    for(k=(size-1); k>0; k/=2)
    
        if(rank<=k)
        
            if(rank<=(k/2))
            
                //receiving the buffers from different processes and computing them
                MPI_Recv(rec_buffer, count, MPI_INT, MPI_ANY_SOURCE, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
                for(i=0; i<count; i++)
                
                    res[i] += rec_buffer[i];
                
            
            else
            
                MPI_Send(res, count, MPI_INT, k-rank, 0, MPI_COMM_WORLD);
            
        
    

但问题是,与 MPI_Reduce 函数本身相比,这段代码的性能要差得多。

那么我该如何进一步优化呢?如果更好,我可以做些什么不同的事情?我不能使 sum 循环多线程,因为我们需要在单个线程中执行它。我可以优化求和循环,但不确定如何以及从哪里开始。

对于一个非常基本的问题,我深表歉意,但我真的开始涉足 HPC 领域。谢谢!

【问题讨论】:

您说您将数组发送到根节点并在那里计算总和。为什么不在每个进程中建立总和,只向根发送一个整数? @maraca 我需要一个由多个数组的总和组成的数组。例如,如果“a”是每个进程中的一个数组,我想要的结果是 result = a(from process 0) + a(from process 1) + a (from process 2) ... 等等...结果最终将是一个数组。 这里是 Open MPI github.com/open-mpi/ompi/blob/master/ompi/mca/coll/base/…使用的各种算法 一个微优化可以改为使用if(rank &lt;= k/2) MPI_Recv ... else if (rank &lt;= k) MPI_Send... 。可能会稍微改善分支情况。 【参考方案1】:

您的第二种方法是正确的,因为您进行了相同数量的通信,但您已经并行化了 reduce 操作(在您的情况下为 sum)和通信(因为您在子集之间进行通信)。您通常会像 Reduction operator 中描述的那样执行 reduce 操作。

但是,您可能想尝试使用 MPI_Isend 和 MPI_Irecv 进行异步通信以提高性能并更接近 MPI_Reduce 性能。

@GillesGouillardet 提供了一个实现,你可以看到代码中的通信是用 isend 和 irecv 完成的(查找“MCA_PML_CALL(isend”和“MCA_PML_CALL(irecv”)

【讨论】:

以上是关于在总和上创建优化的归约的主要内容,如果未能解决你的问题,请参考以下文章

Java8中Stream的归约与收集

通俗地解释下密码学中的归约证明

CUDA:重载共享内存以实现多个数组的归约方法

如何修复“ValueError:零大小数组到没有标识的归约操作 fmin”

通俗地解释下密码学中的归约证明

通俗地解释下密码学中的归约证明