MPI 主进程不等待其他进程计算
MPI master process not waiting for other procs to calculate
您好,我是使用 MPI 编程的新手。我正在尝试将两个矩阵相乘(一个 NxN 矩阵 (A) 和一个 Nx1 (B) 矩阵)以获得结果 C 矩阵 (Nx1)。每个进程都应该计算矩阵 C 中的一行(元素),但是只有进程 0(我的主进程)计算正确,因为它似乎没有等待其他进程完成计算。我也不确定非主进程是否正确发送结果(或者他们是否需要?)。这是我的代码:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "mpi.h"
#define PRINT_VECS 1
#define MAX_RAND 100
#define MASTER 0
#define COLUMNS_B 1
#define N 4
void init_vec(int *vec, int len);
void print_vec(const char *label, int *vec, int len);
void init_vec(int *vec, int len)
{
int i;
for (i = 0; i < len; i++)
{
vec[i] = rand() % MAX_RAND;
}
}
void print_vec(const char *label, int *vec, int len)
{
#if PRINT_VECS
printf("%s", label);
int i;
for (i = 0; i < len; i++)
{
printf("%d ", vec[i]);
}
printf("\n\n");
#endif
}
void init_matrix(int** matrix, int rows, int cols)
{
int i,j;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
matrix[i][j] = rand() % MAX_RAND;
}
}
}
void print_matrix(int** matrix, int rows, int cols)
{
int i;
for (i = 0; i < rows; i++)
{
printf("|");
int j;
for (j = 0; j < cols; j++)
{
printf("%d ", matrix[i][j]);
}
printf("|\n");
}
}
int main(int argc, char *argv[])
{
int my_rank;
int num_procs;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank); //grab this process's rank
MPI_Comm_size(MPI_COMM_WORLD, &num_procs); //grab the total num of processes
int results[num_procs]; // used to store the partial sum computed
int rows, cols, colsB;
rows = N;
cols = N;
colsB = COLUMNS_B;
int **A; // N x N Matrix
int B[N]; // N x 1 Matrix
int **C; // N x 1 Matrix
double start_time; // use these for timing
double stop_time;
if (my_rank == MASTER)
{
printf("Number of processes: %d\n", num_procs);
printf("N: %d\n", N);
srand(time(NULL));
// init A
int i;
A = malloc(rows * sizeof *A);
for (i = 0; i < rows; i++)
{
A[i] = malloc(cols * sizeof *A[i]);
}
init_matrix(A, rows, cols);
printf("Matrix A:\n");
print_matrix(A, rows, cols);
// init B
init_vec(B, N);
print_vec("Matrix B:\n", B, N);
// init C
C = malloc(rows * sizeof *C);
for (i = 0; i < rows; i++)
{
C[i] = malloc(colsB * sizeof *C[i]);
}
start_time = MPI_Wtime();
}
MPI_Bcast(B, N, MPI_INT, 0, MPI_COMM_WORLD);
//MPI_Bcast(A, N, MPI_INT, 0, MPI_COMM_WORLD);
int row = my_rank;
int my_sum = 0;
int i;
if (my_rank < N)
{
for (i = 0; i < N; i++)
{
int num = A[row][i] * B[i];
my_sum = my_sum + num;
}
C[row] = &my_sum;
printf("HAI FROM PROCESS %d! I will calculate row %d. My calculation: %d\n", my_rank, row, my_sum);
}
//MPI_Gather(&C, 1, MPI_INT, results, 1, MPI_INT, 0, MPI_COMM_WORLD);
if (my_rank == MASTER)
{
stop_time = MPI_Wtime();
printf("\nMatrix C:\n");
print_matrix(C, rows, colsB);
printf("Total time (sec): %f\n", stop_time - start_time);
}
MPI_Finalize();
return EXIT_SUCCESS;;
}
我很确定我已经接近了,但我只是遗漏了一些东西。我已经尝试通过广播 A 矩阵添加一些注释掉的语句,and/or 调用 MPI_GATHER,但除了主过程之外似乎没有任何过程给出结果,所以很明显我'我还在做错事。这是一些示例输出:
Number of processes: 28
N: 4
Matrix A:
|11 30 69 24 |
|83 38 66 71 |
|68 71 27 33 |
|58 5 50 10 |
Matrix B:
1 58 81 44
HAI FROM PROCESS 0! I will calculate row 0. My calculation: 8396
Matrix C:
|8396 |
|-2107258888 |
|-2107258920 |
|-2107258888 |
Total time (sec): 0.000078
所以 proc 0 计算正确,但是我的错误消息是 proc 1 出现段错误,我不知道为什么。我得到的错误是:
mpirun noticed that process rank 1 with PID 0 exited on signal 11 (Segmentation fault).
任何帮助将不胜感激!
在C
中,一个二维矩阵是一个指针数组而这是行主要的,这意味着一个二维矩阵是一个指针数组,并且给定指针指向一行(不是列)。
也就是说,MPI
期望行在连续的内存中,因此,指针数组不适合 MPI。
静态数组很适合,但如果需要动态数组,则需要分配矩阵"all at once",然后手动构建指针数组。
所以你可以替换
A = malloc(rows * sizeof *A);
for (i = 0; i < rows; i++)
{
A[i] = malloc(cols * sizeof *A[i]);
}
和
A = (int **)malloc(cols * sizeof(int *);
A[0] = (int *)malloc(cols * rows * sizeof(int));
for (i = 1; i < cols; i++)
{
A[i] = A[i-1] + rows;
}
然后您就可以使用
广播您的矩阵
MPI_Bcast(A[0], cols*rows, MPI_INT, 0, MPI_COMM_WORLD);
详细解释请参考MPI_Bcast a dynamic 2d array
fwiw,我不明白你关于 C
数据的逻辑。
据我所知,这是一个简单的向量,所以像这样声明它并且不要玩指针(因为 MPI 不会正确处理它们)
这是你的程序,有固定的问题:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "mpi.h"
#define PRINT_VECS 1
#define MAX_RAND 100
#define MASTER 0
#define COLUMNS_B 1
#define N 4
void init_vec(int *vec, int len);
void print_vec(const char *label, int *vec, int len);
void init_vec(int *vec, int len)
{
int i;
for (i = 0; i < len; i++)
{
vec[i] = rand() % MAX_RAND;
}
}
void print_vec(const char *label, int *vec, int len)
{
#if PRINT_VECS
printf("%s", label);
int i;
for (i = 0; i < len; i++)
{
printf("%d ", vec[i]);
}
printf("\n\n");
#endif
}
void init_matrix(int** matrix, int rows, int cols)
{
int i,j;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
matrix[i][j] = rand() % MAX_RAND;
}
}
}
void print_matrix(int** matrix, int rows, int cols)
{
int i;
for (i = 0; i < rows; i++)
{
printf("|");
int j;
for (j = 0; j < cols; j++)
{
printf("%d ", matrix[i][j]);
}
printf("|\n");
}
}
int main(int argc, char *argv[])
{
int my_rank;
int num_procs;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank); //grab this process's rank
MPI_Comm_size(MPI_COMM_WORLD, &num_procs); //grab the total num of processes
int results[num_procs]; // used to store the partial sum computed
int rows, cols, colsB, k;
rows = N;
cols = N;
colsB = COLUMNS_B;
int **A; // N x N Matrix
int B[N]; // N x 1 Matrix
int C[N]; // N x 1 Matrix
// Allocate memory for the NxN matrix on all processes
A = (int**) malloc(N * sizeof(int*));
for(k=0;k<N;k++)
A[k]= (int*) malloc(N * sizeof(int));
double start_time; // use these for timing
double stop_time;
if (my_rank == MASTER)
{
printf("Number of processes: %d\n", num_procs);
printf("N: %d\n", N);
srand(time(NULL));
// Initilize arrays on root only
init_matrix(A, rows, cols);
printf("Matrix A:\n");
print_matrix(A, rows, cols);
init_vec(B, N);
print_vec("Matrix B:\n", B, N);
start_time = MPI_Wtime();
}
// Be consistent with names vs. values to avoid bugs
MPI_Bcast(B, N, MPI_INT, MASTER, MPI_COMM_WORLD);
for (k=0; k<N; k++)
MPI_Bcast(&(A[k][0]), N, MPI_INT, MASTER, MPI_COMM_WORLD);
int row = my_rank;
int my_sum = 0;
int i,num;
if (my_rank < N)
{
for (i = 0; i < N; i++)
{
num = A[row][i] * B[i];
my_sum = my_sum + num;
}
C[row] = my_sum;
printf("HAI FROM PROCESS %d! I will calculate row %d. My calculation: %d\n", my_rank, row, my_sum);
}
MPI_Gather(&C[row], 1, MPI_INT, &C[row], 1, MPI_INT, MASTER, MPI_COMM_WORLD);
if (my_rank == MASTER)
{
stop_time = MPI_Wtime();
print_vec("Matrix C:\n", C, N);
printf("Total time (sec): %f\n", stop_time - start_time);
}
// Free matrix A
for(k=0;k<N;k++)
free(A[k]);
free(A);
MPI_Finalize();
return EXIT_SUCCESS;
}
如评论中所述,在这种情况下,您需要为所有进程上的所有矩阵分配内存。该过程与程序仅在根进程上执行的 A 和 B 的初始化不同。这里 A 是使用 malloc
分配的,而 C 是静态分配的,并且进一步以与 B 相同的方式用作向量。这不是必需的,但似乎是更好的选择,因为 C 是一维数组并且在本质上等同于B。
B 像以前一样广播到所有进程,但程序使用 MASTER
而不是 0,因此当您偶然更改 MASTER
的值时,它的所有出现也会更改。这通常是一个很好的编程习惯,在新代码中随处适用。
A 的广播方式简单但效率肯定低于@Gilles Gouailardet 建议的方式 - 该程序只是单独广播 A 的每一行,
for (k=0; k<N; k++)
MPI_Bcast(&(A[k][0]), N, MPI_INT, MASTER, MPI_COMM_WORLD);
这与行优先排序以及 A 中第 k 行的这 N 个元素被连续访问的事实有关。如果 A 是按列发送的,这将失败。
其余更改是将 my_sum
的值而不是指向它的指针分配给 C[row]
、C[row] = my_sum;
和收集操作:
MPI_Gather(&C[row], 1, MPI_INT, &C[row],
1, MPI_INT, MASTER, MPI_COMM_WORLD);
此处每个进程将其值 C[row]
发送到根进程上的 C[row]
。 C 使用 print_vec
函数打印在根上。
您好,我是使用 MPI 编程的新手。我正在尝试将两个矩阵相乘(一个 NxN 矩阵 (A) 和一个 Nx1 (B) 矩阵)以获得结果 C 矩阵 (Nx1)。每个进程都应该计算矩阵 C 中的一行(元素),但是只有进程 0(我的主进程)计算正确,因为它似乎没有等待其他进程完成计算。我也不确定非主进程是否正确发送结果(或者他们是否需要?)。这是我的代码:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "mpi.h"
#define PRINT_VECS 1
#define MAX_RAND 100
#define MASTER 0
#define COLUMNS_B 1
#define N 4
void init_vec(int *vec, int len);
void print_vec(const char *label, int *vec, int len);
void init_vec(int *vec, int len)
{
int i;
for (i = 0; i < len; i++)
{
vec[i] = rand() % MAX_RAND;
}
}
void print_vec(const char *label, int *vec, int len)
{
#if PRINT_VECS
printf("%s", label);
int i;
for (i = 0; i < len; i++)
{
printf("%d ", vec[i]);
}
printf("\n\n");
#endif
}
void init_matrix(int** matrix, int rows, int cols)
{
int i,j;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
matrix[i][j] = rand() % MAX_RAND;
}
}
}
void print_matrix(int** matrix, int rows, int cols)
{
int i;
for (i = 0; i < rows; i++)
{
printf("|");
int j;
for (j = 0; j < cols; j++)
{
printf("%d ", matrix[i][j]);
}
printf("|\n");
}
}
int main(int argc, char *argv[])
{
int my_rank;
int num_procs;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank); //grab this process's rank
MPI_Comm_size(MPI_COMM_WORLD, &num_procs); //grab the total num of processes
int results[num_procs]; // used to store the partial sum computed
int rows, cols, colsB;
rows = N;
cols = N;
colsB = COLUMNS_B;
int **A; // N x N Matrix
int B[N]; // N x 1 Matrix
int **C; // N x 1 Matrix
double start_time; // use these for timing
double stop_time;
if (my_rank == MASTER)
{
printf("Number of processes: %d\n", num_procs);
printf("N: %d\n", N);
srand(time(NULL));
// init A
int i;
A = malloc(rows * sizeof *A);
for (i = 0; i < rows; i++)
{
A[i] = malloc(cols * sizeof *A[i]);
}
init_matrix(A, rows, cols);
printf("Matrix A:\n");
print_matrix(A, rows, cols);
// init B
init_vec(B, N);
print_vec("Matrix B:\n", B, N);
// init C
C = malloc(rows * sizeof *C);
for (i = 0; i < rows; i++)
{
C[i] = malloc(colsB * sizeof *C[i]);
}
start_time = MPI_Wtime();
}
MPI_Bcast(B, N, MPI_INT, 0, MPI_COMM_WORLD);
//MPI_Bcast(A, N, MPI_INT, 0, MPI_COMM_WORLD);
int row = my_rank;
int my_sum = 0;
int i;
if (my_rank < N)
{
for (i = 0; i < N; i++)
{
int num = A[row][i] * B[i];
my_sum = my_sum + num;
}
C[row] = &my_sum;
printf("HAI FROM PROCESS %d! I will calculate row %d. My calculation: %d\n", my_rank, row, my_sum);
}
//MPI_Gather(&C, 1, MPI_INT, results, 1, MPI_INT, 0, MPI_COMM_WORLD);
if (my_rank == MASTER)
{
stop_time = MPI_Wtime();
printf("\nMatrix C:\n");
print_matrix(C, rows, colsB);
printf("Total time (sec): %f\n", stop_time - start_time);
}
MPI_Finalize();
return EXIT_SUCCESS;;
}
我很确定我已经接近了,但我只是遗漏了一些东西。我已经尝试通过广播 A 矩阵添加一些注释掉的语句,and/or 调用 MPI_GATHER,但除了主过程之外似乎没有任何过程给出结果,所以很明显我'我还在做错事。这是一些示例输出:
Number of processes: 28
N: 4
Matrix A:
|11 30 69 24 |
|83 38 66 71 |
|68 71 27 33 |
|58 5 50 10 |
Matrix B:
1 58 81 44
HAI FROM PROCESS 0! I will calculate row 0. My calculation: 8396
Matrix C:
|8396 |
|-2107258888 |
|-2107258920 |
|-2107258888 |
Total time (sec): 0.000078
所以 proc 0 计算正确,但是我的错误消息是 proc 1 出现段错误,我不知道为什么。我得到的错误是:
mpirun noticed that process rank 1 with PID 0 exited on signal 11 (Segmentation fault).
任何帮助将不胜感激!
在C
中,一个二维矩阵是一个指针数组而这是行主要的,这意味着一个二维矩阵是一个指针数组,并且给定指针指向一行(不是列)。
也就是说,MPI
期望行在连续的内存中,因此,指针数组不适合 MPI。
静态数组很适合,但如果需要动态数组,则需要分配矩阵"all at once",然后手动构建指针数组。
所以你可以替换
A = malloc(rows * sizeof *A);
for (i = 0; i < rows; i++)
{
A[i] = malloc(cols * sizeof *A[i]);
}
和
A = (int **)malloc(cols * sizeof(int *);
A[0] = (int *)malloc(cols * rows * sizeof(int));
for (i = 1; i < cols; i++)
{
A[i] = A[i-1] + rows;
}
然后您就可以使用
广播您的矩阵MPI_Bcast(A[0], cols*rows, MPI_INT, 0, MPI_COMM_WORLD);
详细解释请参考MPI_Bcast a dynamic 2d array
fwiw,我不明白你关于 C
数据的逻辑。
据我所知,这是一个简单的向量,所以像这样声明它并且不要玩指针(因为 MPI 不会正确处理它们)
这是你的程序,有固定的问题:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "mpi.h"
#define PRINT_VECS 1
#define MAX_RAND 100
#define MASTER 0
#define COLUMNS_B 1
#define N 4
void init_vec(int *vec, int len);
void print_vec(const char *label, int *vec, int len);
void init_vec(int *vec, int len)
{
int i;
for (i = 0; i < len; i++)
{
vec[i] = rand() % MAX_RAND;
}
}
void print_vec(const char *label, int *vec, int len)
{
#if PRINT_VECS
printf("%s", label);
int i;
for (i = 0; i < len; i++)
{
printf("%d ", vec[i]);
}
printf("\n\n");
#endif
}
void init_matrix(int** matrix, int rows, int cols)
{
int i,j;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
matrix[i][j] = rand() % MAX_RAND;
}
}
}
void print_matrix(int** matrix, int rows, int cols)
{
int i;
for (i = 0; i < rows; i++)
{
printf("|");
int j;
for (j = 0; j < cols; j++)
{
printf("%d ", matrix[i][j]);
}
printf("|\n");
}
}
int main(int argc, char *argv[])
{
int my_rank;
int num_procs;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank); //grab this process's rank
MPI_Comm_size(MPI_COMM_WORLD, &num_procs); //grab the total num of processes
int results[num_procs]; // used to store the partial sum computed
int rows, cols, colsB, k;
rows = N;
cols = N;
colsB = COLUMNS_B;
int **A; // N x N Matrix
int B[N]; // N x 1 Matrix
int C[N]; // N x 1 Matrix
// Allocate memory for the NxN matrix on all processes
A = (int**) malloc(N * sizeof(int*));
for(k=0;k<N;k++)
A[k]= (int*) malloc(N * sizeof(int));
double start_time; // use these for timing
double stop_time;
if (my_rank == MASTER)
{
printf("Number of processes: %d\n", num_procs);
printf("N: %d\n", N);
srand(time(NULL));
// Initilize arrays on root only
init_matrix(A, rows, cols);
printf("Matrix A:\n");
print_matrix(A, rows, cols);
init_vec(B, N);
print_vec("Matrix B:\n", B, N);
start_time = MPI_Wtime();
}
// Be consistent with names vs. values to avoid bugs
MPI_Bcast(B, N, MPI_INT, MASTER, MPI_COMM_WORLD);
for (k=0; k<N; k++)
MPI_Bcast(&(A[k][0]), N, MPI_INT, MASTER, MPI_COMM_WORLD);
int row = my_rank;
int my_sum = 0;
int i,num;
if (my_rank < N)
{
for (i = 0; i < N; i++)
{
num = A[row][i] * B[i];
my_sum = my_sum + num;
}
C[row] = my_sum;
printf("HAI FROM PROCESS %d! I will calculate row %d. My calculation: %d\n", my_rank, row, my_sum);
}
MPI_Gather(&C[row], 1, MPI_INT, &C[row], 1, MPI_INT, MASTER, MPI_COMM_WORLD);
if (my_rank == MASTER)
{
stop_time = MPI_Wtime();
print_vec("Matrix C:\n", C, N);
printf("Total time (sec): %f\n", stop_time - start_time);
}
// Free matrix A
for(k=0;k<N;k++)
free(A[k]);
free(A);
MPI_Finalize();
return EXIT_SUCCESS;
}
如评论中所述,在这种情况下,您需要为所有进程上的所有矩阵分配内存。该过程与程序仅在根进程上执行的 A 和 B 的初始化不同。这里 A 是使用 malloc
分配的,而 C 是静态分配的,并且进一步以与 B 相同的方式用作向量。这不是必需的,但似乎是更好的选择,因为 C 是一维数组并且在本质上等同于B。
B 像以前一样广播到所有进程,但程序使用 MASTER
而不是 0,因此当您偶然更改 MASTER
的值时,它的所有出现也会更改。这通常是一个很好的编程习惯,在新代码中随处适用。
A 的广播方式简单但效率肯定低于@Gilles Gouailardet 建议的方式 - 该程序只是单独广播 A 的每一行,
for (k=0; k<N; k++)
MPI_Bcast(&(A[k][0]), N, MPI_INT, MASTER, MPI_COMM_WORLD);
这与行优先排序以及 A 中第 k 行的这 N 个元素被连续访问的事实有关。如果 A 是按列发送的,这将失败。
其余更改是将 my_sum
的值而不是指向它的指针分配给 C[row]
、C[row] = my_sum;
和收集操作:
MPI_Gather(&C[row], 1, MPI_INT, &C[row],
1, MPI_INT, MASTER, MPI_COMM_WORLD);
此处每个进程将其值 C[row]
发送到根进程上的 C[row]
。 C 使用 print_vec
函数打印在根上。