我正在尝试使用 MPI 和非阻塞通信在 C 中实现 Cannon 的矩阵乘法算法。我已经在http://siber.cankaya.edu.tr/ozdogan/GraduateParallelComputing.old/ceng505/node133.html尝试了示例代码,但我无法让它工作。
使用单个节点执行时它工作正常,但不仅如此,它还没有完成。
我正在尝试在 4 个节点上使用随机 4*4 矩阵。从我所能收集到的信息中,除了 0 级的 printf 进程完成了函数的执行之外,我完全没有调试工具,但是其他进程在第 68 行的 MPI_Wait 处卡住了。我对 C 和并行编程很陌生,不知道是什么错误的。
编辑:在调试过程中,我发现了一件令人难以置信的莫名其妙的事情——调用 MPI_Barrier 似乎会挂起整个程序。
乘法函数完成后,我在 main 中调用 MPI_Barrier。为了使调试更容易一点,我决定将函数代码分成几部分,并用屏障将它们分开。将屏障放置在主计算循环的末尾(这样每个进程都必须完成一次迭代才能开始下一个进程)导致循环甚至没有达到第二次迭代。
似乎当单个进程在非阻塞发送/接收和随后对 MPI_Wait 的调用之后到达屏障时,它会导致其他进程无限期地等待并且永远不会到达屏障。
这是一个示例代码:
void generateArray(int * vector, int size){
int i;
for (i = 0; i < size; i ++){
vector[i] = rand()%10 + 1;
}
}
int test_size = 4;
int main( int argc, char **argv )
{
MPI_Init (&argc, &argv);
int comm_size, myrank;
int my2drank, mycoords[2];
MPI_Comm_size(MPI_COMM_WORLD, &comm_size);
MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
MPI_Request requests[4];
MPI_Status status[4];
MPI_Comm comm_2d;
int dims[2], periods[2];
dims[0] = dims[1] = sqrt(comm_size);
periods[0] = periods[1] = 1;
MPI_Cart_create(MPI_COMM_WORLD, 2, dims, periods, 1, &comm_2d);
int sizelocal = test_size/dims[0];
srand(time(NULL));
int a[sizelocal*sizelocal], b[sizelocal*sizelocal];
generateArray(a, sizelocal*sizelocal);
generateArray(b, sizelocal*sizelocal);
MPI_Comm_rank(comm_2d, &my2drank);
MPI_Cart_coords(comm_2d, my2drank, 2, mycoords);
int uprank, downrank, leftrank, rightrank;
MPI_Cart_shift(comm_2d, 0, -1, &rightrank, &leftrank);
MPI_Cart_shift(comm_2d, 1, -1, &downrank, &uprank);
int *buffersA[2], *buffersB[2];
buffersA[0] = a;
buffersA[1] = (int *)malloc(sizelocal*sizelocal*sizeof(int));
buffersB[0] = b;
buffersB[1] = (int *)malloc(sizelocal*sizelocal*sizeof(int));
int shiftsource, shiftdest;
MPI_Cart_shift(comm_2d, 0, -mycoords[0], &shiftsource, &shiftdest);
MPI_Sendrecv_replace(buffersA[0], sizelocal*sizelocal, MPI_INT,shiftdest, 1, shiftsource, 1, comm_2d, &status[0]);
MPI_Cart_shift(comm_2d, 1, -mycoords[1], &shiftsource, &shiftdest);
MPI_Sendrecv_replace(buffersB[0], sizelocal*sizelocal, MPI_INT,shiftdest, 1, shiftsource, 1, comm_2d, &status[0]);
printf("Rank %d at point 1\n", my2drank);
int i;
for (i = 0; i < 2; i ++){
printf("Rank %d started iteration %d\n", my2drank, i);
MPI_Isend(buffersA[i%2], sizelocal*sizelocal, MPI_INT,leftrank, 1, comm_2d, &requests[0]);
MPI_Isend(buffersB[i%2], sizelocal*sizelocal, MPI_INT,uprank, 1, comm_2d, &requests[1]);
MPI_Irecv(buffersA[(i+1)%2], sizelocal*sizelocal, MPI_INT,rightrank, 1, comm_2d, &requests[2]);
MPI_Irecv(buffersB[(i+1)%2], sizelocal*sizelocal, MPI_INT,downrank, 1, comm_2d, &requests[3]);
MPI_Waitall(4, requests, status);
printf("Rank %d stopped waiting in iteration %d\n", my2drank, i);
MPI_Barrier(comm_2d);
}
printf("Rank %d at point 2\n", my2drank);
MPI_Barrier(MPI_COMM_WORLD);
MPI_Finalize();
return 0;
}
这是输出:
Rank 0 at point 1
Rank 0 started iteration 0
Rank 1 at point 1
Rank 1 started iteration 0
Rank 2 at point 1
Rank 2 started iteration 0
Rank 3 at point 1
Rank 3 started iteration 0
Rank 0 stopped waiting in iteration 0