打开MPI Waitall()分段错误

时间:2017-11-13 13:06:29

标签: c segmentation-fault mpi

我是MPI的新手,我试图开发一个非阻塞程序(使用Isend和Irecv)。功能非常基础(它具有教育意义):

  • 有一个进程(等级0)谁是主服务器并从从服务器接收消息(等级1-P)。主人只收到结果。
  • 奴隶生成一个0到 R 之间的 N 随机数的数组,然后他们用这些数字做一些操作(同样,它仅用于教育目的,操作没有任何意义)
  • 整个过程(操作+发送数据)完成 M 次(这仅用于比较不同的实现;阻塞和非阻塞)

当我调用MPI_waitall()函数时,我在主进程中遇到了分段错误

#include <stdio.h>
#include <stdlib.h>
#include "mpi.h"
#include <math.h>
#include <time.h>
#define M 1000      //Number of times
#define N 2000      //Quantity of random numbers
#define R 1000      //Max value of random numbers

double SumaDeRaices (double*);

int main(int argc, char* argv[]) {
    int         yo;            /* rank of process      */
    int         p;             /* number of processes  */
    int         dest;          /* rank of receiver     */

    /* Start up MPI */
    MPI_Init(&argc, &argv);

    /* Find out process rank  */
    MPI_Comm_rank(MPI_COMM_WORLD, &yo);

    /* Find out number of processes */
    MPI_Comm_size(MPI_COMM_WORLD, &p);

    MPI_Request  reqs[p-1];
    MPI_Status   stats[p-1];   

    if (yo == 0) {
        int i,j;
        double result;
        clock_t inicio,fin;

        inicio = clock();

        for(i = 0; i<M; i++){ //M times
            for(j = 1; j<p; j++){ //for every slave
                MPI_Irecv(&result, sizeof(double), MPI_DOUBLE, j, i, MPI_COMM_WORLD, &reqs[j-1]);
            }
            MPI_Waitall(p-1,reqs,stats); //wait all slaves (SEG_FAULT)
        }
        fin = clock()-inicio;

        printf("Tiempo total de ejecucion %f segundos \n", ((double)fin)/CLOCKS_PER_SEC);   
    }
    else {
        double* numAleatorios = (double*) malloc( sizeof(double) * ((double) N) ); //array with numbers
        int i,j;
        double resultado; 
        dest=0;

        for(i=0; i<M; i++){ //again, M times
            for(j=0; j<N; j++){
                numAleatorios[j] = rand() % R ;
            }
            resultado = SumaDeRaices(numAleatorios);
            MPI_Isend(&resultado,sizeof(double), MPI_DOUBLE, dest, i, MPI_COMM_WORLD,&reqs[p-1]); //send result to master
        }
    }

    /* Shut down MPI */
    MPI_Finalize();

    exit(0);
} /* main */



double SumaDeRaices (double* valores){
    int i;
    double sumaTotal = 0.0;

    //Raices cuadradas de los valores y suma de estos   
    for(i=0; i<N; i++){
        sumaTotal = sqrt(valores[i]) + sumaTotal;
    }

    return sumaTotal;
}

1 个答案:

答案 0 :(得分:2)

您的代码存在一些问题。首先,在您的Isend中,您可以多次传递&resultado,而无需等到上一次非阻塞操作完成。在确保操作完成之前,不允许重复使用传递给Isend的缓冲区。

相反,我建议您使用普通发送,因为与同步发送(SSend)相反,正常阻塞发送只要您可以重用缓冲区就会返回。

其次,不需要使用消息标签。我建议你只需将标签设置为0.在性能方面,它只是更快。

第三,结果不应该是一个简单的变量,而是一个大小至少为(p-1)的数组

第四,我不建议您在堆栈上分配数组,如MPI_Request和MPI_Status,如果大小不是已知的小数字。在这种情况下,数组的大小为(p-1),因此您最好将malloc用于此数据结构。

第五,如果您不检查状态,请使用MPI_STATUSES_IGNORE

而不是sizeof(double),你应该指定项目数量(1)。

但当然绝对最好的版本只是使用MPI_Gather。

此外,通常没有理由不在根节点上运行计算。

这是一个稍微重写的例子:

#include <stdio.h>
#include <stdlib.h>
#include "mpi.h"
#include <math.h>
#include <time.h>
#define M 1000      //Number of times
#define N 2000      //Quantity of random numbers
#define R 1000      //Max value of random numbers

double SumaDeRaices (double* valores)
{

  int i;
  double sumaTotal = 0.0;

  //Raices cuadradas de los valores y suma de estos
  for(i=0; i<N; i++) {
    sumaTotal = sqrt(valores[i]) + sumaTotal;
  }

  return sumaTotal;
}


int main(int argc, char* argv[]) {
  int         yo;            /* rank of process      */
  int         p;             /* number of processes  */

  /* Start up MPI */
  MPI_Init(&argc, &argv);

  /* Find out process rank  */
  MPI_Comm_rank(MPI_COMM_WORLD, &yo);

  /* Find out number of processes */
  MPI_Comm_size(MPI_COMM_WORLD, &p);

  double *result;
  clock_t inicio, fin;
  double *numAleatorios;
  if (yo == 0) {
    inicio = clock();
  }

  numAleatorios = (double*) malloc( sizeof(double) * ((double) N) ); //array with numbers
  result = (double *) malloc(sizeof(double) * p);

  for(int i = 0; i<M; i++){ //M times
    for(int j=0; j<N; j++) {
      numAleatorios[j] = rand() % R ;
    }
    double local_result = SumaDeRaices(numAleatorios);
    MPI_Gather(&local_result, 1, MPI_DOUBLE, result, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); //send result to master
  }

  if (yo == 0) {
    fin = clock()-inicio;

    printf("Tiempo total de ejecucion %f segundos \n", ((double)fin)/CLOCKS_PER_SEC);
  }

  free(numAleatorios);

  /* Shut down MPI */
  MPI_Finalize();
} /* main */