【问题标题】:MPI Get Processor with Minimum valueMPI 获取具有最小值的处理器
【发布时间】:2012-03-06 07:49:22
【问题描述】:

在 MPI 中,我正在对一个值进行缩减操作(最小值)。这工作正常,但我如何获取最小值来自的处理器编号并请求该处理器获取更多信息(或使用 reduce 操作发送附加数据)?

【问题讨论】:

    标签: c mpi reduce


    【解决方案1】:

    如果您不介意将每个值在本地与整数索引(在这种情况下使用本地排名的值填充)进行配对,您可以使用 MPI_MINLOC or MPI_MAXLOC 内置操作来减少;或者编写自己的 MPI 缩减运算符以包含多个索引等内容相当容易

    更新添加: 使用内置运算符 MINLOC 或 MAXLOC,不是传入单个值来查找最小值,而是传入该值加上一个整数索引。该索引可以具有您想要的任何值,但它“跟随”另一个值。 MPI 内置了“对”数据类型 - MPI_DOUBLE_INT 用于双精度 + 整数,或 MPI_2INT 用于两个整数,您可以使用。

    假设你想找到一个整数数组的最小值,以及它位于哪个 MPI 任务上。像往常一样,你在每个任务上找到你的局部最小值,然后做 reduce;但这次你也将它与一个整数配对,在这种情况下你的排名:

    #include <stdio.h>
    #include <stdlib.h>
    #include <mpi.h>
    
    int main(int argc, char **argv) {
    
        int rank, size;
        const int locn=5;
        int localarr[locn];
    
        MPI_Init(&argc, &argv);
        MPI_Comm_rank(MPI_COMM_WORLD, &rank);
        MPI_Comm_size(MPI_COMM_WORLD, &size);
    
        srand(rank);
        for (int i=0; i<locn; i++) 
            localarr[i] = rand() % 100;
    
        for (int proc=0; proc<size; proc++) {
            if (rank == proc) {
                printf("Rank %2d has values: ",rank);
                for (int i=0; i<locn; i++)
                    printf(" %d ", localarr[i]);
                printf("\n");
            }
            MPI_Barrier(MPI_COMM_WORLD);
        }
    
        int localres[2];
        int globalres[2];
        localres[0] = localarr[0];
        for (int i=1; i<locn; i++) 
            if (localarr[i] < localres[0]) localres[0] = localarr[i];
    
        localres[1] = rank;
    
        MPI_Allreduce(localres, globalres, 1, MPI_2INT, MPI_MINLOC, MPI_COMM_WORLD);
    
        if (rank == 0) {
            printf("Rank %d has lowest value of %d\n", globalres[1], globalres[0]);
        }
    
        MPI_Finalize();
    
        return 0;
    }
    

    运行你会得到:

    $ mpirun -np 5 ./minloc
    Rank  0 has values:  83  86  77  15  93 
    Rank  1 has values:  83  86  77  15  93 
    Rank  2 has values:  90  19  88  75  61 
    Rank  3 has values:  46  85  68  40  25 
    Rank  4 has values:  1  83  74  26  63 
    Rank 4 has lowest value of 1
    

    如果您要减少的值不是整数(例如,双精度数),您可以创建一个包含减少值和整数索引的结构,并使用适当的 MPI 对数据类型。 (例如,MPI_DOUBLE_INT)。

    进一步更新:好吧,只是为了好玩,使用我们自己的归约操作和我们自己的类型来实现两个索引:

    #include <stdio.h>
    #include <stdlib.h>
    #include <mpi.h>
    
    typedef struct dbl_twoindex_struct {
        double val;
        int    rank;
        int    posn;
    } dbl_twoindex;
    
    
    void minloc_dbl_twoindex(void *in, void *inout, int *len, MPI_Datatype *type){
        /* ignore type, just trust that it's our dbl_twoindex type */
        dbl_twoindex *invals    = in;
        dbl_twoindex *inoutvals = inout;
    
        for (int i=0; i<*len; i++) {
            if (invals[i].val < inoutvals[i].val) {
                inoutvals[i].val  = invals[i].val;
                inoutvals[i].rank = invals[i].rank;
                inoutvals[i].posn = invals[i].posn;
            }
        }
    
        return;
    }
    
    
    int main(int argc, char **argv) {
    
        int rank, size;
        const int locn=5;
        double localarr[locn];
    
        dbl_twoindex local, global;
    
        MPI_Init(&argc, &argv);
        MPI_Comm_rank(MPI_COMM_WORLD, &rank);
        MPI_Comm_size(MPI_COMM_WORLD, &size);
    
        /* create our new data type */
        MPI_Datatype mpi_dbl_twoindex;
        MPI_Datatype types[3] = { MPI_DOUBLE, MPI_INT, MPI_INT };
        MPI_Aint disps[3] = { offsetof(dbl_twoindex, val),
                         offsetof(dbl_twoindex, rank),
                         offsetof(dbl_twoindex, posn),  };
        int lens[3] = {1,1,1};
        MPI_Type_create_struct(3, lens, disps, types, &mpi_dbl_twoindex);
        MPI_Type_commit(&mpi_dbl_twoindex);
    
       /* create our operator */
        MPI_Op mpi_minloc_dbl_twoindex;
        MPI_Op_create(minloc_dbl_twoindex, 1, &mpi_minloc_dbl_twoindex);
    
        srand(rank);
        for (int i=0; i<locn; i++)
            localarr[i] = 1.*rand()/RAND_MAX;
    
        for (int proc=0; proc<size; proc++) {
            if (rank == proc) {
                printf("Rank %2d has values: ",rank);
                for (int i=0; i<locn; i++)
                    printf(" %8.4lf ", localarr[i]);
                printf("\n");
            }
            MPI_Barrier(MPI_COMM_WORLD);
        }
    
        local.val  = localarr[0];
        local.posn = 0;
        for (int i=1; i<locn; i++)
            if (localarr[i] < local.val) {
                    local.val  = localarr[i];
                    local.posn = i;
            }
        local.rank = rank;
    
        MPI_Allreduce(&local, &global, 1, mpi_dbl_twoindex, mpi_minloc_dbl_twoindex, MPI_COMM_WORLD);
    
        if (rank == 0) {
            printf("Rank %d has lowest value of %8.4lf in position %d.\n", global.rank, global.val, global.posn);
        }
    
        MPI_Op_free(&mpi_minloc_dbl_twoindex);
        MPI_Type_free(&mpi_dbl_twoindex);
        MPI_Finalize();
    
        return 0;
    }
    

    跑步给予

    $ mpirun -np 5 ./minloc2
    Rank  0 has values:    0.8402    0.3944    0.7831    0.7984    0.9116 
    Rank  1 has values:    0.8402    0.3944    0.7831    0.7984    0.9116 
    Rank  2 has values:    0.7010    0.8097    0.0888    0.1215    0.3483 
    Rank  3 has values:    0.5614    0.2250    0.3931    0.4439    0.2850 
    Rank  4 has values:    0.9165    0.1340    0.1912    0.2601    0.2143 
    Rank 2 has lowest value of   0.0888 in position 2.
    

    【讨论】:

    • 你能详细说明或举例说明吗?
    • 谢谢,帮了大忙!是否可以定义类似 MPI_DOUBLE_2INT 的东西,这样我就可以为每个双精度发送多个密钥?
    • 我认为除了内置类型之外,您必须编写自己的操作,但这不会那么难。
    • @JamesCotter :好的,上面是一个“滚动我们自己”的示例,带有一个双精度和两个整数。
    • @JonathanDursi:在用户定义的函数中,如何在不强制转换的情况下从void* 转到dbl_twoindex*
    猜你喜欢
    • 2015-12-14
    • 1970-01-01
    • 2015-06-01
    • 2013-07-06
    • 2015-02-03
    • 2021-12-11
    • 2012-04-14
    • 2022-10-23
    • 1970-01-01
    相关资源
    最近更新 更多