我正在使用一些代码,在从 concole 输入实现矩阵 mult 的表大小时遇到了一些问题。
第一个版本适用于:
const int size = 1000;
int mat_a[size][size], mat_b[size][size], mat_c[size][size];
要使用控制台参数,我发现需要实现动态数组分配。不幸的是,我遇到了一个问题:
*** Process received signal ***
Signal: Segmentation fault (11)
Signal code: Address not mapped (1)
Failing at address: 0x7ffd955237f8
我想这个问题可能出在 MPI 函数中,如 Bcast、Scatter 和 Gather。我在 stackovf 中搜索了类似的案例,但我看不到它。
这是代码:
#include <mpi.h>
#include <stdio.h>
#include <iostream>
#include <cstdlib>
#include <cmath>
#include <math.h>
int main(int argc, char *argv[])
{
int taskid, ntasks, mat_start, mat_end, i, j, k;
double start_time; //hold start time
double end_time; // hold end time
MPI_Init (&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &taskid);
MPI_Comm_size(MPI_COMM_WORLD, &ntasks);
int size = 0;
if (argc != 2) {
printf("No arguments");
exit(-1);
}
size = atoi(argv[1]);
if (size < 0 ) {
printf("SIZE: %2d n", size);
exit(-1);
}
int **mat_a = (int **)malloc(sizeof(int *)*size);
int **mat_b = (int **)malloc(sizeof(int *)*size);
int **mat_c = (int **)malloc(sizeof(int *)*size);
for (int z = 0 ; z < size ; z++){
mat_a[z] = (int *)malloc(sizeof(int)*size);
mat_b[z] = (int *)malloc(sizeof(int)*size);
mat_c[z] = (int *)malloc(sizeof(int)*size);
}
mat_start = taskid * size/ntasks;
mat_end = (taskid+1) * size/ntasks;
if (taskid==0) {
for (i = 0; i < size; i++) {
for (j = 0; j < size; j++) {
mat_a[i][j] = (int)(sin(i) * i * j) % 10;
}
}
for (i = 0; i < size; i++) {
for (j = 0; j < size; j++) {
mat_b[i][j] = (int)(cos(j) * (i + j)) % 10;
}
}
}
start_time = MPI_Wtime();
MPI_Bcast (&mat_b, size*size, MPI_INT, 0, MPI_COMM_WORLD);
MPI_Scatter (&mat_a, size*size/ntasks, MPI_INT, mat_a[mat_start], size*size/ntasks, MPI_INT, 0, MPI_COMM_WORLD);
printf("computing slice %d (from row %d to %d)n", taskid, mat_start, mat_end-1);
for (i=mat_start; i<mat_end; i++)
for (j=0; j<size; j++) {
mat_c[i][j]=0;
for (k=0; k<size; k++)
mat_c[i][j] += mat_a[i][k]*mat_b[k][j];
}
MPI_Gather (mat_c[mat_start], size*size/ntasks, MPI_INT, mat_c, size*size/ntasks, MPI_INT, 0, MPI_COMM_WORLD);
end_time = MPI_Wtime();
printf("nRunning Time = %fnn", end_time - start_time);
MPI_Finalize();
return 0;
}
谁能告诉我出了什么问题?
编辑:
谢谢你的回答。我试图实施您的解决方案建议,但没有取得好结果。我将代码的某些部分更改为如下所示:
int **mat_a=(int **)malloc(size*sizeof(int *));
int **mat_b=(int **)malloc(size*sizeof(int *));
int **mat_c=(int **)malloc(size*sizeof(int *));
if(mat_a==NULL){fprintf(stderr,"malloc failedn");exit(1);}
if(mat_b==NULL){fprintf(stderr,"malloc failedn");exit(1);}
if(mat_c==NULL){fprintf(stderr,"malloc failedn");exit(1);}
mat_a[0]=(int*)malloc(size*size*sizeof(int));
mat_b[0]=(int*)malloc(size*size*sizeof(int));
mat_c[0]=(int*)malloc(size*size*sizeof(int));
if(mat_a[0]==NULL){fprintf(stderr,"malloc failedn");exit(1);}
if(mat_b[0]==NULL){fprintf(stderr,"malloc failedn");exit(1);}
if(mat_c[0]==NULL){fprintf(stderr,"malloc failedn");exit(1);}
int ti;
for(ti=1;ti<size;ti++){
mat_a[ti]=&mat_a[0][size*ti];
mat_b[ti]=&mat_a[0][size*ti];
mat_c[ti]=&mat_a[0][size*ti];
}
mat_start = taskid * size/ntasks;
mat_end = (taskid+1) * size/ntasks;
//populating the array ......
start_time = MPI_Wtime();
MPI_Bcast(mat_a[0],size*size, MPI_INT,0,MPI_COMM_WORLD);
//MPI_Bcast (&mat_b, size*size, MPI_INT, 0, MPI_COMM_WORLD);
// MPI_Scatter (&mat_b, size*size/ntasks, MPI_INT, mat_a[mat_start], size*size/ntasks, MPI_INT, 0, MPI_COMM_WORLD);
MPI_Scatter (mat_b[0], size*size/ntasks, MPI_INT, mat_a[mat_start], size*size/ntasks, MPI_INT, 0, MPI_COMM_WORLD);
printf("computing slice %d (from row %d to %d)n", taskid, mat_start, mat_end-1);
for (i=mat_start; i<mat_end; i++)
for (j=0; j<size; j++) {
mat_c[i][j]=0;
for (k=0; k<size; k++)
mat_c[i][j] += mat_a[i][k]*mat_b[k][j];
}
MPI_Gather (mat_c[mat_start], size*size/ntasks, MPI_INT, mat_c, size*size/ntasks, MPI_INT, 0, MPI_COMM_WORLD);
end_time = MPI_Wtime();
printf("nRunning Time = %fnn", end_time - start_time);
MPI_Finalize();
return 0;
}
程序开始运行,甚至打印mat_a(添加打印时),但经过一段时间的延迟,我得到了这个:
[cuda:05167] *** Process received signal ***
[cuda:05167] Signal: Segmentation fault (11)
[cuda:05167] Signal code: (128)
[cuda:05167] Failing at address: (nil)
散而聚可能是抢劫?如何改变,让它最终发挥作用?
问题是你已经用 C 声明了一个 2d 数组,但这不是 MPI 所期望的!
MPI 无法知道您已经给了它一个 2D 数组!MPI 需要一个连续的数组(在您的情况下是整数)。
要解决您的问题,您需要分配伪多维数组!这将保证你的记忆是连续的。在此之后,您将不会遇到分段错误。
内存分配方式的问题在于 2D 数组在内存中不是连续的:malloc()
每行调用一次。请参阅 使用 MPI 在 C 中发送 2D 数组块
若要更改此设置,请使用以下过程:
int n=42;
int** mat_a=malloc(n*sizeof(int*));
if(mat_a==NULL){fprintf(stderr,"malloc failedn");exit(1);}
mat_a[0]=malloc(n*n*sizeof(int));
if(mat_a[0]==NULL){fprintf(stderr,"malloc failedn");exit(1);}
int i;
for(i=1;i<n;i++){
mat_a[i]=&mat_a[0][n*i];
}
...
free(mat_a[0]);
free(mat_a);
其次,指针的值仅对给定过程有意义。因此,通过执行MPI_Bcast(&mat_b,...)
将指针从一个进程发送到另一个进程是错误的。如果在消息后取消引用mat_b
则可能会触发分段错误。可以改为发送缓冲区:
MPI_Bcast(mat_a[0],n*n, MPI_INT,0,MPI_COMM_WORLD);
由mpicc main.c -o main -Wall
编译并由mpirun -np 2 main
运行的最少代码:
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc,char *argv[])
{
int size, rank;
MPI_Init(&argc,&argv);
MPI_Comm_rank(MPI_COMM_WORLD,&rank);
MPI_Comm_size(MPI_COMM_WORLD,&size);
int n=42;
int** mat_a=malloc(n*sizeof(int*));
if(mat_a==NULL){fprintf(stderr,"malloc failedn");exit(1);}
mat_a[0]=malloc(n*n*sizeof(int));
if(mat_a[0]==NULL){fprintf(stderr,"malloc failedn");exit(1);}
int i;
for(i=1;i<n;i++){
mat_a[i]=&mat_a[0][n*i];
}
//populating the array
int j;
if(rank==0){
for(i=0;i<n;i++){
for(j=0;j<n;j++){
mat_a[i][j]=i+j;
}
}
}
// Bcast the array
MPI_Bcast(mat_a[0],n*n, MPI_INT,0,MPI_COMM_WORLD);
if(rank==1){
for(i=0;i<n;i++){
for(j=0;j<n;j++){
printf("%d ",mat_a[i][j] );
}
printf("n");
}
}
free(mat_a[0]);
free(mat_a);
MPI_Finalize();
return 0;
}