MPI_MIN的MPI_Reduce如何工作?

时间:2016-06-20 19:12:46

标签: c mpi

如果我有这段代码:

int main(void) {
    int result=0;
    int num[6] = {1, 2, 4, 3, 7, 1};
    if (my_rank != 0) {
        MPI_Reduce(num, &result, 6, MPI_INT, MPI_MIN, 0, MPI_COMM_WORLD);
    } else {
        MPI_Reduce(num, &result, 6, MPI_INT, MPI_MIN, 0, MPI_COMM_WORLD)
        printf("result = %d\n", result);
    }
}

结果打印为1;

但如果是num[0]=9;然后结果是9

我阅读解决这个问题我必须将变量num定义为数组。 我无法理解函数MPI_Reduce如何与MPI_MIN一起使用。为什么,如果num[0]不等于最小数字,那么我必须将变量num定义为数组?

2 个答案:

答案 0 :(得分:3)

MPI_Reduce执行通信器成员的减少 - 而不是本地数组的成员。 sendbufrecvbuf必须都是size。{/ p>

我认为the standard说得最好:

  

因此,所有进程都提供输入缓冲区和相同长度的输出缓冲区,具有相同类型的元素。每个进程可以提供一个元素,或一系列元素,在这种情况下,组合操作在序列的每个条目上按元素执行。

MPI没有得到阵列中所有元素的最小值,你必须手动完成。

答案 1 :(得分:1)

您可以使用MPI_MIN获取通过缩减传递的最小值。 让我们检查函数声明:

int MPI_Reduce(void* sendbuf, void* recvbuf, int count, MPI_Datatype
                datatype, MPI_Op op, int root, MPI_Comm comm)

每个进程使用缓冲区sendbuff发送它的值(或值数组)。 由root id标识的进程接收缓冲区并将它们存储在缓冲区recvbuf中。从计数中指定从每个其他进程接收的元素数,因此必须使用维recvbuff分配sizeof(datatype)*count。 如果每个进程只有一个要发送的整数(count = 1),那么recvbuff它也是一个整数,如果每个进程有两个整数,那么recvbuff它是一个大小为2的整数数组。看到这个很好{ {3}}进一步解释和漂亮的图片。

现在应该清楚您的代码是错误的,sendbuffrecvbuff必须具有相同的大小,并且不需要条件:if(myrank==0)。简单来说,recvbuff仅对root进程有意义,对其他进程有sendbuff。 在您的示例中,您可以将数组的一个或多个元素分配给不同的进程,然后计算minvalue(如果有与数组中的值一样多的进程)或minvalues数组(如果有多个值而不是进程)。

这是一个工作示例,说明了在简单值(不是数组)的情况下MPI_MIN,MPI_MAX和MPI_SUM(稍微修改自post)的用法。 每个进程根据其等级执行一些工作,并将完成工作所花费的时间发送给根进程。根进程收集时间并输出时间的最小值,最大值和平均值。

#include <stdio.h>
#include <mpi.h>

int myrank, numprocs;

/* just a function to waste some time */
float work()
{
    float x, y;
    if (myrank%2) {
        for (int i = 0; i < 100000000; ++i) {
            x = i/0.001;
            y += x;
        }
    } else {
        for (int i = 0; i < 100000; ++i) {
            x = i/0.001;
            y += x;
        }
    }    
    return y;
}

int main(int argc, char **argv)
{
    int node;

    MPI_Init(&argc,&argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &node);

    printf("Hello World from Node %d\n",node);

   /*variables used for gathering timing statistics*/
    double mytime,   
           maxtime,
           mintime,
           avgtime;

    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
    MPI_Comm_size(MPI_COMM_WORLD, &numprocs);
    MPI_Barrier(MPI_COMM_WORLD);  /*synchronize all processes*/

    mytime = MPI_Wtime();  /*get time just before work section */
    work();
    mytime = MPI_Wtime() - mytime;  /*get time just after work section*/

    /*compute max, min, and average timing statistics*/
    MPI_Reduce(&mytime, &maxtime, 1, MPI_DOUBLE,MPI_MAX, 0, MPI_COMM_WORLD);
    MPI_Reduce(&mytime, &mintime, 1, MPI_DOUBLE, MPI_MIN, 0,MPI_COMM_WORLD);
    MPI_Reduce(&mytime, &avgtime, 1, MPI_DOUBLE, MPI_SUM, 0,MPI_COMM_WORLD);

    /* plot the output */
    if (myrank == 0) {
        avgtime /= numprocs;
        printf("Min: %lf  Max: %lf  Avg:  %lf\n", mintime, maxtime,avgtime);
    }

    MPI_Finalize();

    return 0;
}

如果我在我的OSX笔记本电脑上运行它,这就是我得到的:

urcaurca$ mpirun -n 4 ./a.out
Hello World from Node 3
Hello World from Node 0
Hello World from Node 2
Hello World from Node 1
Min: 0.000974  Max: 0.985291  Avg:  0.493081