【问题标题】:Open MPI Waitall() Segmentation Fault打开 MPI Waitall() 分段错误
【发布时间】:2018-04-26 04:16:54
【问题描述】:

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

  • 有一个进程(等级 0)是主进程并从从属进程(等级 1-P)接收消息。 master 只接收结果。
  • slave 生成​​一个介于 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;
}

【问题讨论】:

  • 您收到 M*p 次,但您只发送 M 次。正确的数字是多少?
  • @mcsim 我为每个进程发送 M 次(所以我发送 M*p 次)
  • 啊。你是对的。

标签: c segmentation-fault mpi


【解决方案1】:

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

我建议您使用普通发送,因为与同步发送 (SSend) 相比,普通阻塞发送会在您可以重用缓冲区时立即返回。

其次,不需要使用消息标签。我建议您将 tag 设置为 0。就性能而言,它只是更快。

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

第四,如果大小不是已知的小数,我不建议您在堆栈上分配数组,例如 MPI_Request 和 MPI_Status。在这种情况下,数组的大小是(p-1),所以你最好使用malloc来做这个数据结构。

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

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

当然,最好的版本就是使用 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 */

【讨论】:

  • 你能找到你对标签的鄙视吗?无论如何,邮件信封仍然必须包含它。检查速度慢吗?
  • @VladimirF 我试图找到一个参考。我记得的一个是“减轻 MPI 消息匹配痛苦”,不幸的是它在付费墙后面。如果您想了解有关本文的更多详细信息,请告诉我。在那里,他们试图解决一个更普遍的无序消息匹配问题,而 AFAIR mpi 标签只会阻碍这个过程,尤其是使用 MPI_TAG_ANY 和 MPI_SOURCE_ANY。
  • 付费墙后面的科学文本并不是不参考它的理由。我通过网络搜索找到了它,我确实可以访问它。我去看看。
  • 我在论文中找不到这样的结论。如果是这样,那么它可能只适用于他们新颖的散列算法。
猜你喜欢
  • 2014-05-07
  • 2017-06-25
  • 2011-12-08
  • 2019-06-26
  • 2012-01-24
  • 2012-05-11
  • 2015-02-18
  • 2011-12-24
  • 2016-03-22
相关资源
最近更新 更多