我是MPI编程的初学者。我试图编写一个程序,动态地接收不同大小的一维数组(100,1000,10000,1000000的倍数等)并将其分散到分配的处理器核心。处理器内核计算接收元素的总和并将总和发回。根进程打印输入数组中元素的总和。
我使用MPI_Scatter()
和MPI_Reduce()
来解决问题。但是,当分配的处理器内核数量为奇数时,某些数据会被遗漏。例如,当我输入数据大小为100和3个进程时 - 只添加了99个元素,最后一个元素被省略。
我搜索了替代方案,发现MPI_Scatterv()
可用于数据的不均匀分布。但是没有任何材料可以指导我实施它。有人能帮我吗?我在这里发布我的代码。提前谢谢。
#include <stdio.h>
#include <mpi.h>
#include <stdlib.h>
void readArray(char * fileName, double ** a, int * n);
int Numprocs, MyRank;
int mpi_err;
#define Root = 0
void init_it(int *argc, char ***argv) {
mpi_err = MPI_Init(argc, argv);
mpi_err = MPI_Comm_rank(MPI_COMM_WORLD, &MyRank);
mpi_err = MPI_Comm_size(MPI_COMM_WORLD, &Numprocs);
}
int main(int argc, char** argv) {
/* .......Variables Initialisation ......*/
int index;
double *InputBuffer, *RecvBuffer, sum=0.0, psum = 0.0;
double ptime = 0.0, Totaltime= 0.0,startwtime = 0.0, endwtime = 0.0;
int Scatter_DataSize;
int DataSize;
FILE *fp;
init_it(&argc,&argv);
if (argc != 2) {
fprintf(stderr, "\n*** Usage: arraySum <inputFile>\n\n");
exit(1);
}
if (MyRank == 0) {
startwtime = MPI_Wtime();
printf("Number of nodes running %d\n",Numprocs);
/*...... Read input....*/
readArray(argv[1], &InputBuffer, &DataSize);
printf("Size of array %d\n", DataSize);
}
if (MyRank!=0) {
MPI_Recv(&DataSize, 1, MPI_INT, 0, 1, MPI_COMM_WORLD, NULL);
}
else {
int i;
for (i=1;i<Numprocs;i++) {
MPI_Send(&DataSize, 1, MPI_INT, i, 1, MPI_COMM_WORLD);
d[i]= i*Numprocs;
}
}
Scatter_DataSize = DataSize / Numprocs;
RecvBuffer = (double *)malloc(Scatter_DataSize * sizeof(double));
MPI_Barrier(MPI_COMM_WORLD);
mpi_err = MPI_Scatter(InputBuffer, Scatter_DataSize, MPI_DOUBLE,
RecvBuffer, Scatter_DataSize, MPI_DOUBLE,
0, MPI_COMM_WORLD);
for (index = 0; index < Scatter_DataSize; index++) {
psum = psum + RecvBuffer[index];
}
//printf("Processor %d computed sum %f\n", MyRank, psum);
mpi_err = MPI_Reduce(&psum, &sum, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
if (MyRank == 0) {
endwtime = MPI_Wtime();
Totaltime = endwtime - startwtime;
printf("Total sum %f\n",sum);
printf("Total time %f\n", Totaltime);
}
MPI_Finalize();
return 0;
}
void readArray(char * fileName, double ** a, int * n) {
int count, DataSize;
double * InputBuffer;
FILE * fin;
fin = fopen(fileName, "r");
if (fin == NULL) {
fprintf(stderr, "\n*** Unable to open input file '%s'\n\n",
fileName);
exit(1);
}
fscanf(fin, "%d\n", &DataSize);
InputBuffer = (double *)malloc(DataSize * sizeof(double));
if (InputBuffer == NULL) {
fprintf(stderr, "\n*** Unable to allocate %d-length array", DataSize);
exit(1);
}
for (count = 0; count < DataSize; count++) {
fscanf(fin, "%lf", &InputBuffer[count]);
}
fclose(fin);
*n = DataSize;
*a = InputBuffer;
}
答案 0 :(得分:0)
Scatter_Datasize的计算:
Scatter_DataSize = DataSize / Numprocs;
只有当DataSize是Numprocs的倍数时,才是正确的,在你的情况下,当Numprocs是偶数时,因为DataSize总是偶数。当Numprocs是奇数时你应该明确地计算余数并将其分配给一个MPI过程,我建议最后一个。
答案 1 :(得分:0)
在您的情况下,您可以使用sendcount[]
MPI_Scatterv
数组进行游戏。实际上,一个简单的实现方法是计算类型Nelement
的元素数量(比如说sendtype
)所有进程但只有一个会有所启发。其中一个进程(例如最后一个进程)将获取剩余数据。在这种情况下,从sendcount[i] = Nelement
到i
(0
的索引p-2
的{{1}}是通讯器中的进程数,对于您p
)。然后,流程MPI_COMM_WORLD
将获得p-1
。关于位移数组sendcount[p-1] = DataSize-Nelement*(p-1)
,您只需指定从中获取传出数据以处理i的位移(以元素数量)(参见[1]第161页)。对于前面的示例,这将是:
displs[]
如果您确定其他流程 for (i=0; i<p; ++i)
displs[i]=Nelement*i;
必须计算其他数据,请考虑为流程q
设置好displs[q+1]
q+1
。
[1] MPI:消息传递接口标准(版本3.1):http://www.mpi-forum.org/docs/mpi-3.1/mpi31-report.pdf