并行红/黑连续过度放松(SOR)实现中的一些错误

时间:2012-01-24 18:05:59

标签: c mpi parallel-processing

我的任务之一是使用MPI实现RED / BLACK SOR算法。网格被划分为检查板,每次迭代分为红色和黑色两个阶段。在每个阶段期间,算法计算网格的红色或黑色非边界点。其余的实现类似于wiki中的定义。

完整代码:顺序here,并行here

这是顺序实现

iteration = 0;
do {
    maxdiff = 0.0;
    for ( phase = 0; phase < 2 ; phase++){
        for ( i = 1 ; i < N-1 ; i++ ){
            for ( j = 1 + (even(i) ^ phase); j < N-1 ; j += 2 ){
                Gnew = stencil(G,i,j);
                diff = fabs(Gnew - G[i][j]);
                if ( diff > maxdiff )
                    maxdiff = diff;
                G[i][j] = G[i][j] + omega * (Gnew-G[i][j]);
            }
        }
    }
    iteration++;
} while (maxdiff > stopdiff);

对于并行实现,首先对不同节点平均划分网格(列方式)。 例如,如果网格大小为8x8且节点3,则我们将网格划分为这些节点上的8x3,8x3,8x2。 在通信期间,数据与节点的左右邻居交换。下图应该清楚地描述整个过程。

/* Initializing MPI */
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &totalnodes);
MPI_Comm_rank(MPI_COMM_WORLD, &mynode);

// divide grid equally among different nodes
range(1, N - 1, totalnodes, mynode, &jsta, &jend);

// neigboring nodes
inext = mynode + 1;
iprev = mynode - 1;

iteration = 0;
do {
    maxdiff = 0.0;
    for ( phase = 0; phase < 2 ; phase++){

        // exchange column with neigboring node
        exchange(phase);

        for ( i = 1 ; i < N-1 ; i++ ){          // row

            for ( j = jsta + (even(i) ^ phase); j <= jend ; j += 2 ){   // column

                Gnew = stencil(G,i,j);
                diff = fabs(Gnew - G[i][j]);
                if ( diff > maxdiff )
                    maxdiff = diff;
                G[i][j] = G[i][j] + omega * (Gnew-G[i][j]);
            }
        }
    }

    MPI_Allreduce(&maxdiff, &diff, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);
    maxdiff = diff;

    iteration++;
} while (maxdiff > stopdiff);

MPI_Barrier(MPI_COMM_WORLD);
MPI_Finalize();

图描述了网格划分和邻居如何通信的方式。 Figure describes how grid is divided and neighbors communicate.

问题是,并行和顺序SOR的最终结果似乎变化了几位。 需要一个新的配对眼睛来浏览代码来跟踪这个错误,我认为节点之间的通信工作正常。

$ cc -o sor-seq sor-seq.c -lm      
$ ./sor-seq 8 -print
    Running 8 x 8 SOR
    6.006      5.525      5.330      5.251      5.234      5.276      5.417      5.799 
    6.621      6.204      5.984      5.879      5.850      5.892      6.032      6.338 
    6.952      6.687      6.523      6.432      6.395      6.409      6.483      6.640 
    7.181      7.069      6.988      6.931      6.891      6.864      6.852      6.857 
    7.382      7.420      7.429      7.414      7.373      7.306      7.203      7.059 
    7.607      7.799      7.896      7.920      7.884      7.782      7.595      7.294 
    7.926      8.273      8.436      8.488      8.459      8.344      8.101      7.643 
    8.506      8.929      9.088      9.136      9.120      9.033      8.821      8.298 


$ mpicc -o sor-par sor-par.c   
$ mpirun -n 3 ./sor-seq 8 -print
    Running 8 x 8 SOR
    5.940      5.383      5.092      4.882      4.677      4.425      4.072      3.507
    6.496      5.939      5.542      5.201      4.839      4.392      3.794      2.950
    6.786      6.334      5.938      5.542      5.086      4.512      3.761      2.773
    6.994      6.672      6.334      5.942      5.450      4.809      3.964      2.873
    7.197      7.028      6.784      6.442      5.965      5.308      4.414      3.228
    7.445      7.457      7.335      7.075      6.660      6.045      5.157      3.896
    7.807      8.020      8.022      7.864      7.555      7.055      6.273      5.032
    8.443      8.795      8.868      8.805      8.640      8.348      7.848      6.920

    Node: 0
         5.940      5.383      5.092      4.882      0.000      0.000      0.000      0.000 
         6.496      5.939      5.542      5.201      0.000      0.000      0.000      0.000 
         6.786      6.334      5.938      5.542      0.000      0.000      0.000      0.000 
         6.994      6.672      6.334      5.942      0.000      0.000      0.000      0.000 
         7.197      7.028      6.784      6.442      0.000      0.000      0.000      0.000 
         7.445      7.457      7.335      7.075      0.000      0.000      0.000      0.000 
         7.807      8.020      8.022      7.864      0.000      0.000      0.000      0.000 
         8.443      8.795      8.868      8.805      0.000      0.000      0.000      0.000 

    Node: 1
         0.000      0.000      5.092      4.882      4.677      4.425      4.072      0.000 
         0.000      0.000      5.542      5.201      4.839      4.392      3.794      0.000 
         0.000      0.000      5.938      5.542      5.086      4.512      3.761      0.000 
         0.000      0.000      6.334      5.942      5.450      4.809      3.964      0.000 
         0.000      0.000      6.784      6.442      5.965      5.308      4.414      0.000 
         0.000      0.000      7.335      7.075      6.660      6.045      5.157      0.000 
         0.000      0.000      8.022      7.864      7.555      7.055      6.273      0.000 
         0.000      0.000      8.868      8.806      8.640      8.348      7.848      0.000 

    Node: 2
         0.000      0.000      0.000      0.000      0.000      4.425      4.072      3.507 
         0.000      0.000      0.000      0.000      0.000      4.392      3.794      2.950 
         0.000      0.000      0.000      0.000      0.000      4.512      3.761      2.773 
         0.000      0.000      0.000      0.000      0.000      4.809      3.964      2.873 
         0.000      0.000      0.000      0.000      0.000      5.308      4.414      3.228 
         0.000      0.000      0.000      0.000      0.000      6.045      5.157      3.896 
         0.000      0.000      0.000      0.000      0.000      7.055      6.273      5.032 
         0.000      0.000      0.000      0.000      0.000      8.348      7.848      6.920

2 个答案:

答案 0 :(得分:0)

你有没有想过尝试调试器?当我为MPI调试器公司工作时,我非常有偏见,但我刚下载了你的代码,并在Allinea DDT中尝试了它,并且当它检测到读取超出结束时它停止在stencil()中你的数组,最初是由进程7。

要重现这一点,请使用“-g”编译代码以获得调试支持,并从http://www.allinea.com获取Allinea DDT,安装它,然后打开内存调试(并确保配置了“Guard Pages”)在上面,在内存调试设置中有1页。)

运行您的程序,例如8个进程,您很快就会在几秒钟内找到答案。

祝你好运!

大卫

答案 1 :(得分:0)

这看起来很可疑:

MPI_Isend(bufs1, icnt1, MPI_DOUBLE, iprev, 1, MPI_COMM_WORLD, &ireqs1);
MPI_Isend(bufs2, icnt2, MPI_DOUBLE, inext, 1, MPI_COMM_WORLD, &ireqs2);

MPI_Irecv(bufr1, N, MPI_DOUBLE, iprev, 1, MPI_COMM_WORLD, &ireqr1);
MPI_Irecv(bufr2, N, MPI_DOUBLE, inext, 1, MPI_COMM_WORLD, &ireqr2);

MPI_Wait(&ireqs1, &istatus);
MPI_Wait(&ireqs2, &istatus);
MPI_Wait(&ireqr1, &istatus);
MPI_Wait(&ireqr2, &istatus);

我本来期望的是:

MPI_Isend(bufs1, icnt1, MPI_DOUBLE, iprev, 1, MPI_COMM_WORLD, &ireqs1);
MPI_Isend(bufs2, icnt2, MPI_DOUBLE, inext, 1, MPI_COMM_WORLD, &ireqs2);

MPI_Wait(&ireqs1, &istatus);
MPI_Wait(&ireqs2, &istatus);

MPI_Irecv(bufr1, N, MPI_DOUBLE, iprev, 1, MPI_COMM_WORLD, &ireqr1);
MPI_Irecv(bufr2, N, MPI_DOUBLE, inext, 1, MPI_COMM_WORLD, &ireqr2);

MPI_Wait(&ireqs1, &istatus);
MPI_Wait(&ireqs2, &istatus);

可能根本不需要中间两个wait()。