#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include <mpi.h>
#include <malloc.h>
#include <time.h>
#define M 4
#define K 4
#define N 4
void initial(int *array, int size)
{
for (int i = 0; i < size; i++)
{
array[i] = (int)(rand() % 10 + 1);
}
}
void printMatrix(int *array, int row, int col)
{
int *p = array;
for (int y = 0; y < row; y++)
{
printf("第%d行:", y);
for (int x = 0; x < col; x++)
{
printf("%5d", p[x]);
}
p = p + col;
printf("\n");
}
}
void multiplicateMatrix(int *array_A, int *array_B, int *array_C, int MM, int KK, int NN)
{
for (int i = 0; i < MM; i++)
{
for (int j = 0; j < NN; j++)
{
int sum = 0;
for (int k = 0; k < KK; k++)
{
sum += array_A[i*KK + k] * array_B[k*NN + j];
}
array_C[i*NN + j] = sum; /*结果矩阵和*/
}
}
}
int main(int argc, char *argv[])
{
int numprocs,my_rank;
int *A, *B, *result, *local_a, *local_result;
double start,finish,time;
double beginTime, endTime; // time record
int local_m;
int A_xy = M * K;
int B_xy = K * N;
int result_xy = M * N;
A = (int*)malloc(A_xy * sizeof(int));
B = (int*)malloc(B_xy * sizeof(int));
result = (int*)malloc(result_xy * sizeof(int));
MPI_Init(NULL, NULL);
MPI_Comm_size(MPI_COMM_WORLD, &numprocs);
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
if (numprocs == 1)
{
initial(A, M*K);
printf("\n");
printf(" Matrix_A: (%d×%d)\n", M, K);
printMatrix(A, M, K);
initial(B, K*N);
printf(" Matrix_B: (%d×%d)\n", K, N);
printMatrix(B, K, N);
printf("\n");
printf(" ------------------------------------------------------------------------------------\n");
printf(" Computing matrix product using multiplicateMatrix \n");
printf(" ------------------------------------------------------------------------------------\n\n");
/*调用multiplicateMatrixOnHost并进行计时*/
start = clock();
multiplicateMatrix(A, B, result, M, N, K);
finish = clock();
time = (int)(finish - start) / CLOCKS_PER_SEC;
printf(" Matrix_C: (%d×%d) CPU运行时间为:%lfs\n\n\n", M, N, time);
printMatrix(result, M, N);
free(A);
free(B);
free(result);
}
else {
//0号进程用于读取矩阵,分发数据,一部分计算和聚集打印数据MPI_INT
if (my_rank == 0) {
initial(A, M*K);
printf("\n");
printf(" Matrix_A: (%d×%d)\n", M, K);
printMatrix(A, M, K);
initial(B, K*N);
printf(" Matrix_B: (%d×%d)\n", K, N);
printMatrix(B, K, N);
printf("\n");
printf(" ------------------------------------------------------------------------------------\n");
printf(" Computing matrix product using MPI_matrix_scatter \n");
printf(" ------------------------------------------------------------------------------------\n\n");
beginTime = MPI_Wtime();
//分发数据
local_m = M / numprocs;
local_a = (int *)malloc(sizeof(int)*local_m*K); //内存
MPI_Scatter(A, local_m*K, MPI_INT, local_a, local_m*K, MPI_INT, 0, MPI_COMM_WORLD);
// 数组A地址 给每个进程发送数据个数 数据类型 接受缓存地址 接受个数 数据类型 进程编号 通信子
//将b矩阵广播到其他进程
MPI_Bcast(B, K*N, MPI_INT, 0, MPI_COMM_WORLD);
//进行分得的部分计算
local_result = (int *)malloc(sizeof(int)*local_m*N);
int p;
for (int i = 0; i < local_m; i++)
for (int j = 0; j < N; j++)
{
local_result[i*N + j] = 0;
for (p = 0; p < K; p++)
local_result[i*N + j] += local_a[i*K + p] * B[p*N + j];
}
printf("==============================================================================================\n");
printf("进程号:%d local_result值:\n", my_rank);
for (int i = 0; i < local_m; i++)
{
printf("第%d行:",i);
for (int j = 0; j < K; j++)
{
printf("%3d ", local_result[i*K+j]);
}
printf("\n");
}
printf("==============================================================================================\n");
//将各进程结果聚集到result矩阵
MPI_Gather(local_result, local_m*N, MPI_INT, result, local_m*N, MPI_INT, 0, MPI_COMM_WORLD);
printf("==============================================================================================\n");
printf("进程号:%d result值:\n", my_rank);
for (int i = 0; i <M; i++)
{
printf("第%d行:", i);
for (int j = 0; j < N; j++)
{
printf("%3d ", result[i*N + j]);
}
printf("\n");
}
printf("==============================================================================================\n");
//不能整除的情况下a剩余行的处理
int rest = M % numprocs;
if (rest != 0) {
for (int i = M - rest; i < M; i++)
{
for (int j = 0; j < N; j++)
{
result[i*N + j] = 0;
// printf("result 下标:%d,值:%d\n", i*N + j, result[i*N + j]);
for (p = 0; p < K; p++)
{
result[i*N + j] += A[i*K + p] * B[p*N + j];
// printf("进程号:%d,未能整除:i=%d,j=%d,p=%d,A下标:%d,A值:%10lf, B下标:%d, B值:%10lf, result下标:%d, result值:%10lf \n",
// my_rank, i, j, p, i*K + p, A[i*K + p], p*N + j, B[p*N + j], i*N + j, result[i*N + j]);
}
}
}
}
endTime = MPI_Wtime();
// printf(" Matrix_hostRef: (%d×%d) numprocs:%d CPU运行时间为:%lfs\n\n\n\n", M, N, numprocs, endTime - beginTime);
// 将result中结果打印出来
printf(" Matrix_hostRef: (%d×%d) numprocs:%d \n", M, N, numprocs);
printMatrix(result, M, N);
free(A);
free(B);
free(local_a);
free(local_result);
free(result);
}
else {
//其他进程所做的工作和0号进程的计算是一模一样的,所以可以直接复制代码
local_m = M / numprocs;
local_a = (int *)malloc(sizeof(int)*local_m*K);
MPI_Scatter(A, local_m*K, MPI_INT, local_a, local_m*K, MPI_INT, 0, MPI_COMM_WORLD);
MPI_Bcast(B, K*N, MPI_INT, 0, MPI_COMM_WORLD);
local_result = (int *)malloc(sizeof(int)*local_m*N);
for (int i = 0; i < local_m; i++)
for (int j = 0; j < N; j++)
{
local_result[i*N + j] = 0;
for (int p = 0; p < K; p++)
{
local_result[i*N + j] += local_a[i*K + p] * B[p*N + j];
}
}
printf("==============================================================================================\n");
printf("进程号:%d local_result值:\n", my_rank);
for (int i = 0; i < local_m; i++)
{
printf("第%d行: ", i);
for (int j = 0; j < K; j++)
{
printf("%3d ", local_result[i*K + j]);
}
printf("\n");
}
printf("==============================================================================================\n");
MPI_Gather(local_result, local_m*N, MPI_INT, result, local_m*N, MPI_INT, 0, MPI_COMM_WORLD);
free(A);
free(B);
free(local_a);
free(local_result);
free(result);
}
}
MPI_Finalize();
return 0;
}