MPI_Allgather 与 2D 数组

Posted

技术标签:

【中文标题】MPI_Allgather 与 2D 数组【英文标题】:MPI_Allgather with 2D arrays 【发布时间】:2020-02-10 08:43:55 【问题描述】:

我正在尝试根据它们之前的位置计算一些物体的位置。因此,在每个 k 循环中,我需要使用计算并存储在 Cw 数组中的物体的新坐标 (x,y,z) 来更新每个 C 数组。我尝试了 MPI_Allgather,但找不到正确的语法来实现它。

我用问题的串行版本检查了 k=1 的输出,并且 F、V 和 Cw 数组的值是正确的,所以唯一的问题是 MPI_Allgather。为简单起见,现在 dt 变量等于 1。我试过这个,但没有一个工作。第一个仅从 Cw 和另外 2 个值更新第一行 C 数组,但位置错误,其余与开始时填充时相同。第二个给出Segmentation fault

MPI_Allgather(&(Cw[0][0]),length*3,MPI_FLOAT,&(C[0][0]),length*3,MPI_FLOAT,MPI_COMM_WORLD);

MPI_Allgather(Cw,length*3,MPI_FLOAT,C,length*3,MPI_FLOAT,MPI_COMM_WORLD);

这里是代码

float **C,**Cw;

C=malloc(N*sizeof(float*));
Cw=malloc(length*sizeof(float*));

for(i=0;i<length;i++)

    Cw[i]=malloc(3*sizeof(float));


for(i=0;i<N;i++)

    C[i]=malloc(3*sizeof(float));



for(k=0;k<loop;k++)

    for(i=start;i<=end;i++)                      
    
        for(j=0;j<N;j++)                        
        
            if(i!=j)
            
                dx=C[j][0]-C[i][0];
                dy=C[j][1]-C[i][1];
                dz=C[j][2]-C[i][2];

                d=sqrt(pow(dx,2)+pow(dy,2)+pow(dz,2));

                F[i-start][0] -= G*M[i]*M[j]/pow(d,3)*dx;
                F[i-start][1] -= G*M[i]*M[j]/pow(d,3)*dy;
                F[i-start][2] -= G*M[i]*M[j]/pow(d,3)*dz;
            
        
    

    for(i=0;i<length;i++)
    
        for(j=0;j<3;j++)
        
            a=F[i][j]/M[i+start];                 // α=F/m
            V[i][j]=V[i][j]+a*1;                 // V(n+1)=Vn+α*Δt
            Cw[i][j]=C[i+start][j]+V[i][j]*1;    // R(n+1)=Rn+Vn*Δt
        
    

    // where MPI_Allgather takes place

我期望的输出是串行程序提供的 https://drive.google.com/open?id=1fwLu8Jk3JEorFTvNJyOtti3K_zIw0ncw

带有此代码的mpi版本

MPI_Allgather(&(Cw[0][0]),length*3,MPI_FLOAT,&(C[0][0]),length*3,MPI_FLOAT,MPI_COMM_WORLD);

给出这个输出https://drive.google.com/open?id=14cEFFRvNGUN_RK3u8Z31iRDtiTJs6_8I

【问题讨论】:

你是如何声明CwC的? 我在上面的代码中添加了@GillesGouaillardet 您需要在连续内存中分配二维数组。你也可能想要N == length * size(MPI_COMM_WORLD) 【参考方案1】:

再一次,这个指向指针的废话(对于 scicomp):您通过 MPI 传递指向行的指针,而不是内容。

我建议你避免将数组分配为 N 个独立的行,如下所示:

float **C,**Cw;

// I guess that you missed to paste these two lines
C  = malloc( N * sizeof(float*) );    
Cw = malloc( length * sizeof(float*) );

for(i=0;i<length;i++)

    Cw[i]=malloc(3*sizeof(float));


for(i=0;i<N;i++)

    C[i]=malloc(3*sizeof(float));

以这种方式分配的数组在内存中不是线性的,并且不能被 MPI 函数全局使用。当您传递C 时,您传递的只是指针数组。传递&amp;C[0][0],您传递的是前 3 个元素的数组,但其他 3 元素数组在内存中并不连续,因为它们是独立分配的。因此,segfault 是您可以实现的最好结果,随机结果是最差的。

在一个块中分配所需的内存是正确的,MPI函数可以正确处理:

float *C,*Cw;
C  = malloc( N * 3 * sizeof(float) );    
Cw = malloc( length * 3 * sizeof(float) );

并将任何内存访问替换为

            dx=C[j][0]-C[i][0];
            dy=C[j][1]-C[i][1];
            dz=C[j][2]-C[i][2];

            dx=C[3*j+0]-C[3*i+0];
            dy=C[3*j+1]-C[3*i+1];
            dz=C[3*j+2]-C[3*i+2];

这样,传递C会导致正确传递数组内容。

【讨论】:

以上是关于MPI_Allgather 与 2D 数组的主要内容,如果未能解决你的问题,请参考以下文章

使用MPI_Sendrecv实现MPI_Allgather

我想提高 JOIN SQL 性能

在 python 中将 4D 数组与 2D 数组相乘和求和的最快方法?

将 std::next_permutation 与 2D 数组一起使用

cocos2d JS 中的数组拼接与排序

使用 2D 字符数组时将数组作为指针