我正在考虑为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中一样。
我想知道是否有这样的包装,以便我不必重新发明轮子。
感谢。
答案 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_region
和end_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