模仿OpenMP for-loop pragma的MPI包装器

时间:2012-08-27 15:22:30

标签: c parallel-processing mpi openmp

我正在考虑为MPI实现一个模仿OpenMP方式的包装器 并行化循环。

  begin_parallel_region( chunk_size=100 , num_proc=10 );

  for( int i=0 ; i<1000 ; i++ )
  {
       //some computation 
  }

  end_parallel_region();

上面的代码将for循环中的计算分配给10个从MPI处理器。 在进入并行区域时,提供块大小和从处理器的数量。 离开并行区域后,MPI处理器将同步并进入空闲状态。

已编辑以回应高性能标记。

我无意模拟OpenMP的共享内存模型。 我提出这个是因为我需要它。 我正在开发一个从数学函数构建图形所需的库。 在这些数学函数中,通常存在类似下面的循环。

 for( int i=0 ; i<n ; i++ )
 {
          s = s + sin(x[i]);
 }

所以我想首先能够将sin(x [i])分发给从属处理器,最后减少到单个变量,就像在OpenMP中一样。

我想知道是否有这样的包装,以便我不必重新发明轮子。

感谢。

3 个答案:

答案 0 :(得分:6)

没有这样的包装从研究实验室转移到广泛使用。你提出的建议不是重新发明轮子,而是发明飞行汽车

我可以看到你如何建议编写模拟OpenMP共享循环负担的方法的MPI代码,你不太清楚如何建议让MPI模拟OpenMP的共享内存模型?

在一个简单的OpenMP程序中,正如你所建议的那样,10个线程可能会执行10%的大循环迭代,可能会更新大型(共享)数据结构的值。要在MPI中模拟你的狡猾包装内,你要么必须(i)说服单面通信表现得像共享内存(这可能是可行的并且肯定会很困难)或者(ii)将数据分发给所有人进程,让每个进程独立计算10%的结果,然后全部广播结果,以便在执行结束时每个进程都拥有其他进程拥有的所有数据。

在分布式内存硬件上模拟共享内存计算是并行计算的热门话题,始终如一,始终如一。 Google for 分布式共享内存计算并加入其中。

修改

好吧,如果您在各个流程中分发x,那么各个流程可以计算sin(x[i]),您可以使用MPI_Reduce将总和减少到一个流程。

我一定错过了一些关于你的要求的东西,因为我无法理解为什么你要在MPI已经提供的东西之上构建任何上层结构。尽管如此,我对你原来问题的回答仍然是不,你找不到这样的包装而我的所有其余答案都只是评论。

答案 1 :(得分:4)

是的,您可以执行此操作,以执行特定任务。但你不应该。

考虑如何实现这一点;开始部分将分发数据,最终部分将回答:

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

typedef struct state_t {
    int globaln;
    int localn;
    int *locals;
    int *offsets;
    double *localin;
    double *localout;
    double (*map)(double);
} state;

state *begin_parallel_mapandsum(double *in, int n, double (*map)(double)) {
    state *s = malloc(sizeof(state));
    s->globaln = n;
    s->map = map;

    /* figure out decomposition */

    int size, rank;
    MPI_Comm_size(MPI_COMM_WORLD, &size);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);

    s->locals  = malloc(size * sizeof(int));
    s->offsets = malloc(size * sizeof(int));

    s->offsets[0] = 0;

    for (int i=0; i<size; i++) {
        s->locals[i] = (n+i)/size;
        if (i < size-1) s->offsets[i+1] = s->offsets[i] + s->locals[i];
    }

    /* allocate local arrays */
    s->localn   = s->locals[rank];
    s->localin  = malloc(s->localn*sizeof(double));
    s->localout = malloc(s->localn*sizeof(double));


    /* distribute */
    MPI_Scatterv( in, s->locals, s->offsets, MPI_DOUBLE,
                  s->localin, s->locals[rank], MPI_DOUBLE,
                  0, MPI_COMM_WORLD);

    return s;
}

double  end_parallel_mapandsum(state **s) {
    double localanswer=0., answer;

    /* sum up local answers */
    for (int i=0; i<((*s)->localn); i++) {
        localanswer += ((*s)->localout)[i];
    }

    /* and get global result.  Everyone gets answer */
    MPI_Allreduce(&localanswer, &answer, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);

    free( (*s)->localin );
    free( (*s)->localout );
    free( (*s)->locals );
    free( (*s)->offsets );
    free( (*s) );

    return answer;
}


int main(int argc, char **argv) {
    int rank;
    double *inputs;
    double result;
    int n=100;
    const double pi=4.*atan(1.);

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

    if (rank == 0) {
        inputs = malloc(n * sizeof(double));
        for (int i=0; i<n; i++) {
            inputs[i] = 2.*pi/n*i;
        }
    }

    state *s=begin_parallel_mapandsum(inputs, n, sin);

    for (int i=0; i<s->localn; i++) {
        s->localout[i] = (s->map)(s->localin[i]);
    }

    result = end_parallel_mapandsum(&s);

    if (rank == 0) {
        printf("Calculated result: %lf\n", result);
        double trueresult = 0.;
        for (int i=0; i<n; i++) trueresult += sin(inputs[i]);
        printf("True  result: %lf\n", trueresult);
    }

    MPI_Finalize();

}

这种常数分配/收集是一个糟糕的通信负担,总结了一些数字,并且与整个分布式内存计算模型是对立的。

首先,共享内存方法 - OpenMP,pthreads,IPP,你有什么 - 关于扩展计算更快;关于在同一块内存中投入更多处理器。另一方面,分布式内存计算是关于扩展计算更大;关于使用更多的资源,特别是内存,可以在一台计算机上找到。使用MPI的一大胜利是当你处理不能适合任何一个节点的内存的问题集时。因此,在进行分布式内存计算时,您可以避免在任何一个地方拥有所有数据。

即使您只是使用MPI on-node来使用所有处理器,也必须牢记这一基本方法。上面的分散/聚集方法只会破坏性能。更惯用的分布式内存计算方法是用于已经分发数据的程序逻辑 - 也就是说,上面的begin_parallel_regionend_parallel_region已经构建在一开始就进入你的循环上面的代码。然后,每个循环只是

 for( int i=0 ; i<localn ; i++ )
    {
          s = s + sin(x[i]);
    }

当您需要在任务之间交换数据(或减少结果,或者您拥有的内容)时,您可以调用MPI函数来执行这些特定任务。

答案 2 :(得分:1)

MPI是必须的,还是只是尝试在群集上运行类似OpenMP的代码?在后一种情况下,我建议你看看英特尔的Cluster OpenMP:

http://www.hpcwire.com/hpcwire/2006-05-19/openmp_on_clusters-1.html