gpt4 book ai didi

c - MPI 非阻塞通信循环在一定数量的节点上发生故障

转载 作者:行者123 更新时间:2023-11-30 15:16:32 24 4
gpt4 key购买 nike

我正在编写一段代码,它可以在一个圆圈中的节点周围传递数据,就像rank0->rank1、rank1->rank2、rank2->rank0一样。

为了测试带宽,添加了一个 for 循环来进行数百次非阻塞通信。

当我使用 5 个或更少的节点时,代码可以工作。但在超过5个节点的情况下,就失败了。

[compute-0-10:21508] 信号:段错误 (11)
[compute-0-10:21508] 信号代码:(128)
[compute-0-10:21508] 地址失败:(nil)

但是,如果我注释掉循环行,仅发送和接收数据一次,则无论节点数量如何,代码都可以正常工作。我真的不知道哪里出了问题。

以下是代码。

int rank, npes;
MPI_Comm_size(MPI_COMM_WORLD,&npes);
MPI_Comm_rank(MPI_COMM_WORLD,&rank);

float* recv_buffer_last = (float*)malloc(sizeof(float)*YMAX*FMAX);
float* recv_buffer_next = (float*)malloc(sizeof(float)*YMAX*FMAX);
float* send_buffer_next = (float*)malloc(sizeof(float)*YMAX*FMAX);
float* send_buffer_last = (float*)malloc(sizeof(float)*YMAX*FMAX);


if(npes >1)
{
MPI_Status reqstat;
MPI_Request send_request;
MPI_Request recv_request;

for(int loop = 0; loop < 100; loop++) //if no loop here,code always works.
{
MPI_Irecv(recv_buffer_last,YMAX*FMAX,MPI_FLOAT,(rank == 0)?(npes - 1):(rank - 1),100,MPI_COMM_WORLD,&recv_request);
MPI_Irecv(recv_buffer_next,YMAX*FMAX,MPI_FLOAT,(rank == npes-1)?0:rank+1,1000,MPI_COMM_WORLD,&recv_request);
MPI_Isend(send_buffer_next,YMAX*FMAX,MPI_FLOAT,(rank == npes -1)?0:rank+1,100,MPI_COMM_WORLD,&send_request);
MPI_Isend(send_buffer_last,YMAX*FMAX,MPI_FLOAT,(rank ==0)?(npes - 1):(rank - 1),1000,MPI_COMM_WORLD,&send_request);
MPI_Waitall(1,&recv_request,&reqstat);
MPI_Waitall(1,&send_request,&reqstat);

}
}
else
{
memcpy(recv_buffer_last,send_buffer_next,sizeof(float)*YMAX*FMAX);
memcpy(recv_buffer_next,send_buffer_last,sizeof(float)*YMAX*FMAX);
}

更新:

感谢大家指出MPI_Waitall的错误,但是进行修改并不能解决我的问题。

在研究了我的代码之后,我发现将动态数组recv_buffer和send_buffer更改为静态数组可以使代码完美运行。

int rank, npes;
MPI_Comm_size(MPI_COMM_WORLD,&npes);
MPI_Comm_rank(MPI_COMM_WORLD,&rank);

/*
float* recv_buffer_last = (float*)malloc(sizeof(float)*YMAX*FMAX);
float* recv_buffer_next = (float*)malloc(sizeof(float)*YMAX*FMAX);
float* send_buffer_next = (float*)malloc(sizeof(float)*YMAX*FMAX);
float* send_buffer_last = (float*)malloc(sizeof(float)*YMAX*FMAX);
*/

float recv_buffer_last[FMAX*YMAX];
float recv_buffer_next[FMAX*YMAX];
float send_buffer_last[FMAX*YMAX];
float send_buffer_next[FMAX*YMAX];

int prev = (rank+npes-1)%npes;
int next = (rank+1)%npes;

if(npes >1)
{
MPI_Request requests[4];
for(int loop = 0; loop < 100; loop++)
{
MPI_Irecv(recv_buffer_last,YMAX*FMAX,MPI_FLOAT,prev,100,MPI_COMM_WORLD,&requests[0]);
MPI_Irecv(recv_buffer_next,YMAX*FMAX,MPI_FLOAT,next,1000,MPI_COMM_WORLD,&requests[1]);
MPI_Isend(send_buffer_next,YMAX*FMAX,MPI_FLOAT,next,100,MPI_COMM_WORLD,&requests[2]);
MPI_Isend(send_buffer_last,YMAX*FMAX,MPI_FLOAT,prev,1000,MPI_COMM_WORLD,&requests[3]);
MPI_Waitall(4,requests,MPI_STATUSES_IGNORE);


}
}
else
{
memcpy(recv_buffer_last,send_buffer_next,sizeof(float)*YMAX*FMAX);
memcpy(recv_buffer_next,send_buffer_last,sizeof(float)*YMAX*FMAX);
}

我想知道是什么造成了差异,这样我就可以避免将来出现类似的问题。

最佳答案

我很确定问题的根源是您在通信结束时没有等待悬而未决的请求,因为您有 2 个 MPI_Irecv() 和 2 个 MPI_Isend() 每个循环,因此发出 4 个请求,但只等待 2 个请求。这意味着在内部,MPI 库将为这些请求分配资源,这些资源永远不会被释放,从而导致达到某些内部限制并导致您遇到的错误。

以下是您的代码的示例:

int rank, npes;
MPI_Comm_size( MPI_COMM_WORLD, &npes );
MPI_Comm_rank( MPI_COMM_WORLD, &rank );

int len = YMAX*FMAX;
float *recv_buffer_last = (float*) malloc( sizeof( float ) * len );
float *recv_buffer_next = (float*) malloc( sizeof( float ) * len );
float *send_buffer_next = (float*) malloc( sizeof( float ) * len );
float *send_buffer_last = (float*) malloc( sizeof( float ) * len );

if ( npes > 1 ) {
MPI_Request requests[4];
int prev = ( rank + npes - 1 ) % npes;
int next = ( rank + 1 ) % npes;
for ( int loop = 0; loop < 100; loop++ ) {
MPI_Irecv( recv_buffer_last, len, MPI_FLOAT, prev, 100, MPI_COMM_WORLD, &requests[0] );
MPI_Irecv( recv_buffer_next, len, MPI_FLOAT, next, 1000, MPI_COMM_WORLD, &requests[1] );
MPI_Isend( send_buffer_next, len, MPI_FLOAT, next, 100, MPI_COMM_WORLD, &requests[2] );
MPI_Isend( send_buffer_last, len, MPI_FLOAT, prev, 1000, MPI_COMM_WORLD, &requests[3] );
MPI_Waitall( 4, requests, MPI_STATUSES_IGNORE );
}
}
else {
memcpy( recv_buffer_last, send_buffer_next, sizeof( float ) * len );
memcpy( recv_buffer_next, send_buffer_last, sizeof( float ) * len);
}

关于c - MPI 非阻塞通信循环在一定数量的节点上发生故障,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33026416/

24 4 0
文章推荐: c# - 根据字符串属性是否包含另一个 List 的任何字符串值来过滤 IEnumerable