要求:对矩阵向量乘法MPI程序进行不同输入规模、不同进程数的执行和计时,并对得到运行时间进行计算分析,据此评价该程序的强扩展性和弱扩展性。最后总结学习心得,撰写实验报告。
提示:分布式程序的各进程执行进度不同步,为了较为准确地计时,需要在计时开始时插入一个Barrier,最后取各进程计时结果的最大值。为方便矩阵的生成和计算结果的验证,可以通过自定义函数直接生成单位矩阵和元素全为1的向量用于计算。要特别注意注意C语言中传递二维数组给函数时,只能以一维数组的形式传递,并在函数内部把一维数组视为二维数组使用。
代码如下:
#include
#include
#include
void Get_input(int my_rank,int *m,int *n)
{
if(my_rank==0){
printf("Please enter m,n:\n");
scanf("%d %d",m,n);
}
MPI_Bcast(m,1,MPI_INT,0,MPI_COMM_WORLD);
MPI_Bcast(n,1,MPI_INT,0,MPI_COMM_WORLD);
}
void Get_matrix(int n, int m, double *local_matrix, int local_m, int my_rank)
{
double *A;
if (!my_rank)
{
A = (double *)malloc(m * n * sizeof(double));
printf("Please enter the matrix:\n");
for (int i = 0; i < m; ++i)
for (int j = 0; j < n; ++j)
scanf("%lf", &A[i * n + j]);
}
MPI_Scatter(A, local_m * n, MPI_DOUBLE, local_matrix, local_m * n, MPI_DOUBLE, 0, MPI_COMM_WORLD);
}
void Print_matrix(int my_rank,int n,int m,int local_m,double *local_matrix,MPI_Comm comm)
{
double *matrix = NULL;
int i,j;
if(my_rank==0)
{
matrix = malloc(m*n*sizeof(double));
MPI_Gather(local_matrix,local_m*n,MPI_DOUBLE,matrix,local_m*n,MPI_DOUBLE,0,comm);
printf("The matrix is:\n");
for(i=0;i<m;++i)
{
for(j=0;j<n;++j)
{
printf("%f ",matrix[i*n+j]);
}
printf("\n");
}
free(matrix);
}
else{
MPI_Gather(local_matrix,local_m*n,MPI_DOUBLE,matrix,local_m*n,MPI_DOUBLE,0,comm);
}
}
void Get_vector(int my_rank,int n,int local_n,double *local_vector,MPI_Comm comm)
{
double *vector = NULL;
int i;
if(my_rank==0)
{
vector=(double *)malloc(n*sizeof(double));
printf("Please enter the vector:\n");
for(i=0;i<n;i++)
{
scanf("%lf",&vector[i]);
}
}
printf("\n");
MPI_Scatter(vector,local_n,MPI_DOUBLE,local_vector,local_n,MPI_DOUBLE,0,comm);
}
void Print_vector(int my_rank,int n,int local_n,double *local_vector,MPI_Comm comm)
{
double *vector = NULL;
int i,j;
if(my_rank==0)
{
vector = malloc(n*sizeof(double));
MPI_Gather(local_vector,local_n,MPI_DOUBLE,vector,local_n,MPI_DOUBLE,0,comm);
printf("The vector is:\n");
for(i=0;i<n;i++){
printf("%f ",vector[i]);
}
printf("\n");
free(vector);
}
else{
MPI_Gather(local_vector,local_n,MPI_DOUBLE,vector,local_n,MPI_DOUBLE,0,comm);
}
}
void Mat_vect_mult(double *local_matrix,double *local_vector,double *local_y,int local_m,int n,int local_n,MPI_Comm comm)
{
int local_i,j;
double *x;
x=malloc(n*sizeof(double));
MPI_Allgather(local_vector,local_n,MPI_DOUBLE,x,local_n,MPI_DOUBLE,comm);
for(local_i=0;local_i<local_m;local_i++)
{
local_y[local_i]=0.0;
for(j=0;j<n;j++)
{
local_y[local_i]+=local_matrix[local_i*n+j]*x[j];
}
}
free(x);
}
void Print_y(int my_rank,double *local_y,int m,int local_m,MPI_Comm comm)
{
double *y=NULL;
int i;
if(my_rank==0){
y=malloc(m*sizeof(double));
MPI_Gather(local_y,local_m,MPI_DOUBLE,y,local_m,MPI_DOUBLE,0,comm);
printf("The vector y is:\n");
for(i=0;i<m;i++)
{
printf("%lf ",y[i]);
}
printf("\n");
free(y);
}
else{
MPI_Gather(local_y,local_m,MPI_DOUBLE,y,local_m,MPI_DOUBLE,0,comm);
}
}
int main()
{
int comm_sz,my_rank,i;
int m,n,local_m,local_n;
double *local_matrix,*local_vector;
double *local_y;
double start,end;
MPI_Init(NULL,NULL);
MPI_Comm_size(MPI_COMM_WORLD,&comm_sz);
MPI_Comm_rank(MPI_COMM_WORLD,&my_rank);
Get_input(my_rank,&m,&n);
local_m=m/comm_sz;
local_n=n/comm_sz;
local_matrix=(double *)malloc(local_m*n*sizeof(double));
local_vector=(double *)malloc(local_n*sizeof(double));
local_y=(double *)malloc(local_m*sizeof(double));
Get_matrix(n,m,local_matrix,local_m,my_rank);
Print_matrix(my_rank,n,m,local_m,local_matrix,MPI_COMM_WORLD);
Get_vector(my_rank,n,local_n,local_vector,MPI_COMM_WORLD);
Print_vector(my_rank,n,local_n,local_vector,MPI_COMM_WORLD);
MPI_Barrier(MPI_COMM_WORLD);
start = MPI_Wtime();
Mat_vect_mult(local_matrix,local_vector,local_y,local_m,n,local_n,MPI_COMM_WORLD);
MPI_Barrier(MPI_COMM_WORLD);
end = MPI_Wtime();
Print_y(my_rank,local_y,m,local_m,MPI_COMM_WORLD);
MPI_Finalize();
if (my_rank == 0) {
printf("Runtime = %f\n", end-start);
}
return 0;
}
反复多次换数据规模进行实验,罗列出表格。
本次实验难度不大,因为在原来的基础上只需要增加计算时间的工具,稍微有难度的地方则是在于由于一般的数据计算时间极快,并不能发现,所以输入的矩阵规模一定要大,但由于我设计的程序是用手动输入所以十分繁琐,不得已通过Python编写了一个写矩阵的程序,在通过全选的方式复制粘贴到矩阵输入处,不过还是十分繁琐,所以一定要注意可以在刚开始就使用读取txt文件的方式,这样能大大简便使用的难度。
该程序实验规模不变,进程数增加,运行时间线性减少,不能维持恒定效率所以该程序不是强可扩展性,但是规模以一定速率扩大效率没有随着进程数增加而降低,所以该程序是可扩展的,该程序规模变大可以通过增加进程数保持效率不变,所以该程序是弱可扩展性的。