MPI Overlapping 使用C语言产生数组求和
MPI Overlapping using C language to produce array summation
我正在学习 MPI 编程并在关注 Whosebug 时遇到了问题。我正在使用相同的 "answered" 示例以增加重叠的方式计算每行的总和。这是一个 2 x 3 数组,我想在这些数组元素达到 MPI_Irecv
时立即计算总和。我在 MPI_Irecv
和 MPI_Wait
之间编辑了我的代码,以便在数组元素可用时立即开始计算。但是当我 运行 代码时,我调用 MPI_Test
的方式似乎无法正常工作。如果你能用一个例子解决这个问题,我将不胜感激。
使用mpirun -np 3 test
0 级将生成数组元素。第一和第二名将计算总和
#include "mpi.h"
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char *argv[])
{
MPI_Init(&argc, &argv);
int world_rank;
MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
int world_size;
MPI_Comm_size(MPI_COMM_WORLD, &world_size);
int tag = 1;
int arr[2][3];
MPI_Request request;
MPI_Status status;
int source = 0;
int dest;
int flag;
printf ("\n--Current Rank: %d\n", world_rank);
//To handle the number of process received by the user will be handled here later
if (world_rank == 0)
{
int i = 1;
int a, b, x, y;
printf("* Rank 0 excecuting\n");
for(x=0; x<2; x++)//Generating the whole 2 by 3 2D array
{
i++;
for ( y = 0; y < 3; y++ )
{
arr[x][y] = i;//first row contain all 2
} //second row contain all 3
}
int subarray_index;
for(subarray_index=0; subarray_index < 2; subarray_index++)
{
dest = subarray_index%(world_size - 1) + 1;
tag = subarray_index;
MPI_Isend(&arr[subarray_index][0], 3, MPI_INT, dest, tag, MPI_COMM_WORLD, &request);
}
}
else
{
int a, b;
for(b=0; b<2/(world_size-1); b++)
{
int sum = 0;
int i;
int my_offset = world_rank-1;
tag = b*(world_size-1) + my_offset;
int subarray = b;
MPI_Irecv(&arr[subarray][0], 3, MPI_INT, source, tag, MPI_COMM_WORLD, &request);
MPI_Test(&request, &flag, &status);//I think there may be an error at MPI_Test too
while (flag != 1)
{
MPI_Test(&request, &flag, &status);
for(i = 0; i<3; i++)
{
//if(!arr[subarray][i])//want to wait till I recive actual array elements
//{//This need to start calculating as soon as array element become avilable
printf("%d) arr[subarray][i]:%d at rank %d\n", tag, arr[subarray][i], world_rank);
sum = arr[subarray][i]+sum;
//}
}
}
printf("\nSum is: %d at rank: %d and tag is:%d\n", sum, world_rank, tag);
MPI_Wait (&request, &status);
}
}
MPI_Finalize();
}
当我输入 mpirun -np 3 test
答案应该是 "Sum is 6" 和 "Sum is 9"
--Current Rank: 2
1) arr[subarray][i]:40896 at rank 2
1) arr[subarray][i]:32767 at rank 2
1) arr[subarray][i]:617513272 at rank 2
1) arr[subarray][i]:40896 at rank 2
1) arr[subarray][i]:32767 at rank 2
1) arr[subarray][i]:617513272 at rank 2
1) arr[subarray][i]:40896 at rank 2
1) arr[subarray][i]:32767 at rank 2
1) arr[subarray][i]:617513272 at rank 2 //all above arr element shows it's empty
1) arr[subarray][i]:3 at rank 2 //following three values are correct and these
1) arr[subarray][i]:3 at rank 2 //are the only three that need to use for summing
1) arr[subarray][i]:3 at rank 2
Sum is: 1909043312 at rank: 2 and tag is:1
--Current Rank: 0
* Rank 0 excecuting
--Current Rank: 1 //here I don't get arr element values as above
Sum is: 0 at rank: 1 and tag is:0
不确定你的问题是什么。但是根据您的描述,我推断进程 1 在已收到消息时到达 MPI_Test
。因此,flag
已经设置并且永远不会进入循环。
另一方面,由于在等待接收消息时无条件地执行求和,因此在等级 2 上您正在添加未初始化的值。
收到消息后才能进行汇总。也就是说,当标志被设置时,它在你的 while 循环之后并且基本上使你的整个构造无效,就像你可以做的那样:
MPI_Irecv(&arr[subarray][0], 3, MPI_INT, source, tag, MPI_COMM_WORLD, &request);
MPI_Wait (&request, &status);
一旦消息可用,等待将 return,这是 MPI_Wait
的要点。现在,以上基本上等同于阻塞 MPI_Recv
.
另一方面,您也要在发送端等待通信在某个时刻完成。您需要为每个 MPI_Isend
单独请求。然后您可以在发送循环后使用 MPI_Waitall
。
因此,您可能想要这样的东西(使用阻塞接收):
#include "mpi.h"
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char *argv[])
{
MPI_Init(&argc, &argv);
int world_rank;
MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
int world_size;
MPI_Comm_size(MPI_COMM_WORLD, &world_size);
int tag = 1;
int arr[2][3];
MPI_Request request[2];
int source = 0;
int dest;
int flag;
printf ("\n--Current Rank: %d\n", world_rank);
//To handle the number of process received by the user will be handled here later
if (world_rank == 0)
{
int i = 1;
int a, b, x, y;
MPI_Status status[2];
printf("* Rank 0 excecuting\n");
for(x=0; x<2; x++)//Generating the whole 2 by 3 2D array
{
i++;
for ( y = 0; y < 3; y++ )
{
arr[x][y] = i;//first row contain all 2
} //second row contain all 3
dest = x%(world_size - 1) + 1;
tag = x;
MPI_Isend(&arr[x][0], 3, MPI_INT, dest, tag, MPI_COMM_WORLD, &request[x]);
}
MPI_Waitall(2, &request[0], &status[0]);
}
else
{
int a, b;
MPI_Status status;
for(b=0; b<2/(world_size-1); b++)
{
int sum = 0;
int i;
int my_offset = world_rank-1;
tag = b*(world_size-1) + my_offset;
int subarray = b;
MPI_Recv(&arr[subarray][0], 3, MPI_INT, source, tag, MPI_COMM_WORLD, &status);
for(i = 0; i<3; i++)
{
//if(!arr[subarray][i])//want to wait till I recive actual array elements
//{//This need to start calculating as soon as array element become avilable
printf("%d) arr[subarray][i]:%d at rank %d\n", tag, arr[subarray][i], world_rank);
sum = arr[subarray][i]+sum;
//}
}
printf("\nSum is: %d at rank: %d and tag is:%d\n", sum, world_rank, tag);
}
}
MPI_Finalize();
}
这会尽快发送值,并在接收到行后立即作用于另一侧。如果该过程要处理多行,您可能仍希望在接收方 post 多次接收,但在这种情况下,您再次需要一个请求数组,您将使用 MPI_Waitany
或 MPI_Waitsome
尽快处理收到的消息。
这里是接收部分MPI_Waitany
:
{
int a, b;
MPI_Status status;
MPI_Request request[2/(world_size-1)];
for(b=0; b<2/(world_size-1); b++)
{
int my_offset = world_rank-1;
tag = b*(world_size-1) + my_offset;
int subarray = b;
MPI_Irecv(&arr[subarray][0], 3, MPI_INT, source, tag, MPI_COMM_WORLD, &request[b]);
}
for(b=0; b<2/(world_size-1); b++)
{
int sum = 0;
int i;
MPI_Waitany(2/(world_size-1), &request[0], &a, &status);
for(i = 0; i<3; i++)
{
printf("%d) arr[subarray][i]:%d at rank %d\n", status.MPI_TAG, arr[a][i], world_rank);
sum = arr[a][i]+sum;
}
printf("\nSum is: %d at rank: %d and tag is:%d\n", sum, world_rank, status.MPI_TAG);
}
}
我正在学习 MPI 编程并在关注 Whosebug MPI_Irecv
时立即计算总和。我在 MPI_Irecv
和 MPI_Wait
之间编辑了我的代码,以便在数组元素可用时立即开始计算。但是当我 运行 代码时,我调用 MPI_Test
的方式似乎无法正常工作。如果你能用一个例子解决这个问题,我将不胜感激。
使用mpirun -np 3 test
0 级将生成数组元素。第一和第二名将计算总和
#include "mpi.h"
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char *argv[])
{
MPI_Init(&argc, &argv);
int world_rank;
MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
int world_size;
MPI_Comm_size(MPI_COMM_WORLD, &world_size);
int tag = 1;
int arr[2][3];
MPI_Request request;
MPI_Status status;
int source = 0;
int dest;
int flag;
printf ("\n--Current Rank: %d\n", world_rank);
//To handle the number of process received by the user will be handled here later
if (world_rank == 0)
{
int i = 1;
int a, b, x, y;
printf("* Rank 0 excecuting\n");
for(x=0; x<2; x++)//Generating the whole 2 by 3 2D array
{
i++;
for ( y = 0; y < 3; y++ )
{
arr[x][y] = i;//first row contain all 2
} //second row contain all 3
}
int subarray_index;
for(subarray_index=0; subarray_index < 2; subarray_index++)
{
dest = subarray_index%(world_size - 1) + 1;
tag = subarray_index;
MPI_Isend(&arr[subarray_index][0], 3, MPI_INT, dest, tag, MPI_COMM_WORLD, &request);
}
}
else
{
int a, b;
for(b=0; b<2/(world_size-1); b++)
{
int sum = 0;
int i;
int my_offset = world_rank-1;
tag = b*(world_size-1) + my_offset;
int subarray = b;
MPI_Irecv(&arr[subarray][0], 3, MPI_INT, source, tag, MPI_COMM_WORLD, &request);
MPI_Test(&request, &flag, &status);//I think there may be an error at MPI_Test too
while (flag != 1)
{
MPI_Test(&request, &flag, &status);
for(i = 0; i<3; i++)
{
//if(!arr[subarray][i])//want to wait till I recive actual array elements
//{//This need to start calculating as soon as array element become avilable
printf("%d) arr[subarray][i]:%d at rank %d\n", tag, arr[subarray][i], world_rank);
sum = arr[subarray][i]+sum;
//}
}
}
printf("\nSum is: %d at rank: %d and tag is:%d\n", sum, world_rank, tag);
MPI_Wait (&request, &status);
}
}
MPI_Finalize();
}
当我输入 mpirun -np 3 test
答案应该是 "Sum is 6" 和 "Sum is 9"
--Current Rank: 2
1) arr[subarray][i]:40896 at rank 2
1) arr[subarray][i]:32767 at rank 2
1) arr[subarray][i]:617513272 at rank 2
1) arr[subarray][i]:40896 at rank 2
1) arr[subarray][i]:32767 at rank 2
1) arr[subarray][i]:617513272 at rank 2
1) arr[subarray][i]:40896 at rank 2
1) arr[subarray][i]:32767 at rank 2
1) arr[subarray][i]:617513272 at rank 2 //all above arr element shows it's empty
1) arr[subarray][i]:3 at rank 2 //following three values are correct and these
1) arr[subarray][i]:3 at rank 2 //are the only three that need to use for summing
1) arr[subarray][i]:3 at rank 2
Sum is: 1909043312 at rank: 2 and tag is:1
--Current Rank: 0
* Rank 0 excecuting
--Current Rank: 1 //here I don't get arr element values as above
Sum is: 0 at rank: 1 and tag is:0
不确定你的问题是什么。但是根据您的描述,我推断进程 1 在已收到消息时到达 MPI_Test
。因此,flag
已经设置并且永远不会进入循环。
另一方面,由于在等待接收消息时无条件地执行求和,因此在等级 2 上您正在添加未初始化的值。
收到消息后才能进行汇总。也就是说,当标志被设置时,它在你的 while 循环之后并且基本上使你的整个构造无效,就像你可以做的那样:
MPI_Irecv(&arr[subarray][0], 3, MPI_INT, source, tag, MPI_COMM_WORLD, &request);
MPI_Wait (&request, &status);
一旦消息可用,等待将 return,这是 MPI_Wait
的要点。现在,以上基本上等同于阻塞 MPI_Recv
.
另一方面,您也要在发送端等待通信在某个时刻完成。您需要为每个 MPI_Isend
单独请求。然后您可以在发送循环后使用 MPI_Waitall
。
因此,您可能想要这样的东西(使用阻塞接收):
#include "mpi.h"
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char *argv[])
{
MPI_Init(&argc, &argv);
int world_rank;
MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
int world_size;
MPI_Comm_size(MPI_COMM_WORLD, &world_size);
int tag = 1;
int arr[2][3];
MPI_Request request[2];
int source = 0;
int dest;
int flag;
printf ("\n--Current Rank: %d\n", world_rank);
//To handle the number of process received by the user will be handled here later
if (world_rank == 0)
{
int i = 1;
int a, b, x, y;
MPI_Status status[2];
printf("* Rank 0 excecuting\n");
for(x=0; x<2; x++)//Generating the whole 2 by 3 2D array
{
i++;
for ( y = 0; y < 3; y++ )
{
arr[x][y] = i;//first row contain all 2
} //second row contain all 3
dest = x%(world_size - 1) + 1;
tag = x;
MPI_Isend(&arr[x][0], 3, MPI_INT, dest, tag, MPI_COMM_WORLD, &request[x]);
}
MPI_Waitall(2, &request[0], &status[0]);
}
else
{
int a, b;
MPI_Status status;
for(b=0; b<2/(world_size-1); b++)
{
int sum = 0;
int i;
int my_offset = world_rank-1;
tag = b*(world_size-1) + my_offset;
int subarray = b;
MPI_Recv(&arr[subarray][0], 3, MPI_INT, source, tag, MPI_COMM_WORLD, &status);
for(i = 0; i<3; i++)
{
//if(!arr[subarray][i])//want to wait till I recive actual array elements
//{//This need to start calculating as soon as array element become avilable
printf("%d) arr[subarray][i]:%d at rank %d\n", tag, arr[subarray][i], world_rank);
sum = arr[subarray][i]+sum;
//}
}
printf("\nSum is: %d at rank: %d and tag is:%d\n", sum, world_rank, tag);
}
}
MPI_Finalize();
}
这会尽快发送值,并在接收到行后立即作用于另一侧。如果该过程要处理多行,您可能仍希望在接收方 post 多次接收,但在这种情况下,您再次需要一个请求数组,您将使用 MPI_Waitany
或 MPI_Waitsome
尽快处理收到的消息。
这里是接收部分MPI_Waitany
:
{
int a, b;
MPI_Status status;
MPI_Request request[2/(world_size-1)];
for(b=0; b<2/(world_size-1); b++)
{
int my_offset = world_rank-1;
tag = b*(world_size-1) + my_offset;
int subarray = b;
MPI_Irecv(&arr[subarray][0], 3, MPI_INT, source, tag, MPI_COMM_WORLD, &request[b]);
}
for(b=0; b<2/(world_size-1); b++)
{
int sum = 0;
int i;
MPI_Waitany(2/(world_size-1), &request[0], &a, &status);
for(i = 0; i<3; i++)
{
printf("%d) arr[subarray][i]:%d at rank %d\n", status.MPI_TAG, arr[a][i], world_rank);
sum = arr[a][i]+sum;
}
printf("\nSum is: %d at rank: %d and tag is:%d\n", sum, world_rank, status.MPI_TAG);
}
}