使用 MPI_Isend() MPI_and Irecv() 时,是否应该使用相同的请求?如果消息已经是一个数组,应该如何传递?
when using MPI_Isend() MPI_and Irecv(), should the pair use the same request? in case the message is already an array, how it should be passed?
在这段代码中,我尝试使用非阻塞发送和接收作为练习进行广播。我有很多问题。
1.Should 我将 Isend() 和 Irecv() 配对使用相同的请求?
2.When消息是一个数组,应该如何传递?在这种情况下,消息或消息?
3.Why 我不能在少于或多于 8 个处理器上 运行 此代码?如果排名不退出,它不应该继续执行而不执行那段代码吗?
4.The 底部的片段是为了一次打印总时间,但 waitall() 不起作用,我不明白为什么。
5. 当传递长于 2^12 的数组时,我得到分段错误,而我已经检查了 Isend() 和 Irecv() 的限制,它们应该处理更大长度的消息。
6.I 使用 long double 来记录时间,这是一种常见的做法还是好的做法?当我使用像 float 或 double 这样的小变量时,我会得到 nan。
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<mpi.h>
int main(int argc, char *argv[]){
MPI_Init(&argc, &argv);
int i, rank, size, ready;
long int N = pow(2, 10);
float* message = (float *)malloc(sizeof(float *) * N + 1);
long double start, end;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
//MPI_Request* request = (MPI_Request *)malloc(sizeof(MPI_Request *) * size);
MPI_Request request[size-1];
/*Stage I: -np 8*/
if(rank == 0){
for(i = 0; i < N; i++){
message[i] = N*rand();
message[i] /= rand();
}
start = MPI_Wtime();
MPI_Isend(&message, N, MPI_FLOAT, 1, 0, MPI_COMM_WORLD, &request[0]);
MPI_Isend(&message, N, MPI_FLOAT, 2, 0, MPI_COMM_WORLD, &request[1]);
MPI_Isend(&message, N, MPI_FLOAT, 4, 0, MPI_COMM_WORLD, &request[3]);
printf("Processor root-rank %d- sent the message...\n", rank);
}
if (rank == 1){
MPI_Irecv(&message, N, MPI_FLOAT, 0, 0, MPI_COMM_WORLD, &request[0]);
MPI_Wait(&request[0], MPI_STATUS_IGNORE);
printf("Processor rank 1 received the message.\n");
MPI_Isend(&message, N, MPI_FLOAT, 3, 0, MPI_COMM_WORLD, &request[2]);
MPI_Isend(&message, N, MPI_FLOAT, 5, 0, MPI_COMM_WORLD, &request[4]);
}
if(rank == 2){
MPI_Irecv(&message, N, MPI_FLOAT, 0, 0, MPI_COMM_WORLD, &request[1]);
MPI_Wait(&request[1], MPI_STATUS_IGNORE);
printf("Processor rank 2 received the message.\n");
MPI_Isend(&message, N, MPI_FLOAT, 6, 0, MPI_COMM_WORLD, &request[5]);
}
if(rank == 3){
MPI_Irecv(&message, N, MPI_FLOAT, 1, 0, MPI_COMM_WORLD, &request[2]);
MPI_Wait(&request[2], MPI_STATUS_IGNORE);
printf("Processor rank 3 received the message.\n");
MPI_Isend(&message, N, MPI_FLOAT, 7, 0, MPI_COMM_WORLD, &request[6]);
}
if(rank == 4){
MPI_Irecv(&message, N, MPI_FLOAT, 0, 0, MPI_COMM_WORLD, &request[3]);
MPI_Wait(&request[3], MPI_STATUS_IGNORE);
printf("Processor rank 4 received the message.\n");
}
if(rank == 5){
MPI_Irecv(&message, N, MPI_FLOAT, 1, 0, MPI_COMM_WORLD, &request[4]);
MPI_Wait(&request[4], MPI_STATUS_IGNORE);
printf("Processor rank 5 received the message.\n");
}
if(rank == 6){
MPI_Irecv(&message, N, MPI_FLOAT, 2, 0, MPI_COMM_WORLD, &request[5]);
MPI_Wait(&request[5], MPI_STATUS_IGNORE);
printf("Processor rank 6 received the message.\n");
}
if(rank == 7){
MPI_Irecv(&message, N, MPI_FLOAT, 3, 0, MPI_COMM_WORLD, &request[6]);
MPI_Wait(&request[6], MPI_STATUS_IGNORE);
printf("Processor rank 7 received the message.\n");
}
/*MPI_Testall(size-1,request,&ready, MPI_STATUS_IGNORE);*/
/* if (ready){*/
end = MPI_Wtime();
printf("Total Time: %Lf\n", end - start);
/*}*/
MPI_Finalize();
}
- 每个 MPI 任务 运行 在其自己的地址 space 中,因此
request[1]
排名 0
和 request[1]
排名之间没有相关性2
。这意味着您不必“配对”请求。也就是说,如果您认为“配对”请求可以提高代码的可读性,即使这不是必需的,您也可能想要这样做。
MPI_Isend()
和MPI_Irecv()
的buffer参数是指向数据开始的指针,这是message
(而不是 &message
) 在这里。
- 如果你 运行 假设有 2 个 MPI 任务,排名
0
上的 MPI_Send(..., dest=2, ...)
将失败,因为 2
是 [=21= 中的无效排名] 通讯器.
- 许多请求在调用
MPI_Waitall()
(这里是 MPI_Testall()
)时未初始化。一种选择是首先将它们全部初始化为 MPI_REQUEST_NULL
.
- 使用
&message
导致内存损坏,这可能解释了崩溃。
- 根据 MPI 标准,原型是
double MPI_Wtime()
,因此您宁愿在此处使用 double
(NaN 可能来自上述内存损坏)
在这段代码中,我尝试使用非阻塞发送和接收作为练习进行广播。我有很多问题。 1.Should 我将 Isend() 和 Irecv() 配对使用相同的请求? 2.When消息是一个数组,应该如何传递?在这种情况下,消息或消息? 3.Why 我不能在少于或多于 8 个处理器上 运行 此代码?如果排名不退出,它不应该继续执行而不执行那段代码吗? 4.The 底部的片段是为了一次打印总时间,但 waitall() 不起作用,我不明白为什么。 5. 当传递长于 2^12 的数组时,我得到分段错误,而我已经检查了 Isend() 和 Irecv() 的限制,它们应该处理更大长度的消息。 6.I 使用 long double 来记录时间,这是一种常见的做法还是好的做法?当我使用像 float 或 double 这样的小变量时,我会得到 nan。
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<mpi.h>
int main(int argc, char *argv[]){
MPI_Init(&argc, &argv);
int i, rank, size, ready;
long int N = pow(2, 10);
float* message = (float *)malloc(sizeof(float *) * N + 1);
long double start, end;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
//MPI_Request* request = (MPI_Request *)malloc(sizeof(MPI_Request *) * size);
MPI_Request request[size-1];
/*Stage I: -np 8*/
if(rank == 0){
for(i = 0; i < N; i++){
message[i] = N*rand();
message[i] /= rand();
}
start = MPI_Wtime();
MPI_Isend(&message, N, MPI_FLOAT, 1, 0, MPI_COMM_WORLD, &request[0]);
MPI_Isend(&message, N, MPI_FLOAT, 2, 0, MPI_COMM_WORLD, &request[1]);
MPI_Isend(&message, N, MPI_FLOAT, 4, 0, MPI_COMM_WORLD, &request[3]);
printf("Processor root-rank %d- sent the message...\n", rank);
}
if (rank == 1){
MPI_Irecv(&message, N, MPI_FLOAT, 0, 0, MPI_COMM_WORLD, &request[0]);
MPI_Wait(&request[0], MPI_STATUS_IGNORE);
printf("Processor rank 1 received the message.\n");
MPI_Isend(&message, N, MPI_FLOAT, 3, 0, MPI_COMM_WORLD, &request[2]);
MPI_Isend(&message, N, MPI_FLOAT, 5, 0, MPI_COMM_WORLD, &request[4]);
}
if(rank == 2){
MPI_Irecv(&message, N, MPI_FLOAT, 0, 0, MPI_COMM_WORLD, &request[1]);
MPI_Wait(&request[1], MPI_STATUS_IGNORE);
printf("Processor rank 2 received the message.\n");
MPI_Isend(&message, N, MPI_FLOAT, 6, 0, MPI_COMM_WORLD, &request[5]);
}
if(rank == 3){
MPI_Irecv(&message, N, MPI_FLOAT, 1, 0, MPI_COMM_WORLD, &request[2]);
MPI_Wait(&request[2], MPI_STATUS_IGNORE);
printf("Processor rank 3 received the message.\n");
MPI_Isend(&message, N, MPI_FLOAT, 7, 0, MPI_COMM_WORLD, &request[6]);
}
if(rank == 4){
MPI_Irecv(&message, N, MPI_FLOAT, 0, 0, MPI_COMM_WORLD, &request[3]);
MPI_Wait(&request[3], MPI_STATUS_IGNORE);
printf("Processor rank 4 received the message.\n");
}
if(rank == 5){
MPI_Irecv(&message, N, MPI_FLOAT, 1, 0, MPI_COMM_WORLD, &request[4]);
MPI_Wait(&request[4], MPI_STATUS_IGNORE);
printf("Processor rank 5 received the message.\n");
}
if(rank == 6){
MPI_Irecv(&message, N, MPI_FLOAT, 2, 0, MPI_COMM_WORLD, &request[5]);
MPI_Wait(&request[5], MPI_STATUS_IGNORE);
printf("Processor rank 6 received the message.\n");
}
if(rank == 7){
MPI_Irecv(&message, N, MPI_FLOAT, 3, 0, MPI_COMM_WORLD, &request[6]);
MPI_Wait(&request[6], MPI_STATUS_IGNORE);
printf("Processor rank 7 received the message.\n");
}
/*MPI_Testall(size-1,request,&ready, MPI_STATUS_IGNORE);*/
/* if (ready){*/
end = MPI_Wtime();
printf("Total Time: %Lf\n", end - start);
/*}*/
MPI_Finalize();
}
- 每个 MPI 任务 运行 在其自己的地址 space 中,因此
request[1]
排名0
和request[1]
排名之间没有相关性2
。这意味着您不必“配对”请求。也就是说,如果您认为“配对”请求可以提高代码的可读性,即使这不是必需的,您也可能想要这样做。 MPI_Isend()
和MPI_Irecv()
的buffer参数是指向数据开始的指针,这是message
(而不是&message
) 在这里。- 如果你 运行 假设有 2 个 MPI 任务,排名
0
上的MPI_Send(..., dest=2, ...)
将失败,因为2
是 [=21= 中的无效排名] 通讯器. - 许多请求在调用
MPI_Waitall()
(这里是MPI_Testall()
)时未初始化。一种选择是首先将它们全部初始化为MPI_REQUEST_NULL
. - 使用
&message
导致内存损坏,这可能解释了崩溃。 - 根据 MPI 标准,原型是
double MPI_Wtime()
,因此您宁愿在此处使用double
(NaN 可能来自上述内存损坏)