1

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

  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 循环。

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

因此,我希望首先能够将 sin(x[i]) 分配给从属处理器,最后减少为单个变量,就像在 OpenMP 中一样。

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

谢谢。

4

3 回答 3

6

没有这样的包装纸已经从研究实验室逃脱并被广泛使用。你的提议与其说是重新发明轮子,不如说是发明飞行汽车

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

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

在分布式内存硬件上模拟共享内存计算是并行计算中的热门话题,一直是,永远都是。谷歌为分布式共享内存计算而加入乐趣。

编辑

好吧,如果您已经x跨进程分布,那么单个进程可以计算sin(x[i]),并且您可以使用MPI_Reduce.

我一定遗漏了您的要求,因为我不明白您为什么要在 MPI 已经提供的基础上构建任何上层建筑。尽管如此,我对您最初问题的回答仍然是不,没有您所寻求的包装,我的所有其他回答都只是评论。

于 2012-08-27T15:47:57.233 回答
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 来使用所有处理器,牢记这种基本方法也很重要。上述分散/收集方法只会降低性能。更惯用的分布式内存计算方法是程序的逻辑已经分布了数据——也就是说,你begin_parallel_regionend_parallel_region上面的代码在一开始就已经内置到循环上面的代码中。然后,每个循环只是

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

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

于 2012-08-28T14:20:34.297 回答
1

MPI 是必须的,还是您只是想在集群上运行类似 OpenMP 的代码?在后一种情况下,我建议您看一下 Intel 的 Cluster OpenMP:

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

于 2012-08-27T15:34:38.913 回答