2012-06-19 127 views
2

我目前正在开发一个项目,我需要使用openmpi来实现并行fft算法。我有一段编译代码,但是当我在群集上运行时,出现了段错误。运行openmpi时出现Segfault错误

我有我的预感,关于事情会出错的地方,但我不认为我有足够的关于指针和引用的理解能够做出有效的修复。

可能出错的第一个块是将数组传递给辅助函数。我相信无论我的循环是不一致的,还是我不了解如何传递这些指针并找回我需要的东西。

第二个可能的点位于实际的mpi_Send/Recv命令中。我发送了openmpi c数据类型不支持的类型,所以我使用mpi_byte类型来发送原始数据。这是一个可行的选择吗?或者我应该寻找一种替代方法。

/* function declarations */ 
double complex get_block(double complex c[], int start, int stop); 

double complex put_block(double complex from[], double complex to[], 
      int start, int stop); 

void main(int argc, char **argv) 
{ 
    /* Initialize MPI */ 
    MPI_Init(&argc, &argv); 

    double complex c[N/p]; 
    int myid; 
    MPI_Comm_rank(MPI_COMM_WORLD, &myid); 
    //printf("My id is %d\n",myid); 

    MPI_Status status; 

    int i; 
    for(i=0;i<N/p;i++){ 
    c[i] = 1.0 + 1.0*I; 
    } 

    int j = log(p)/log(2) + 1; 
    double q; 
    double complex z; 
    double complex w = exp(-2*PI*I/N); 
    double complex block[N/(2*p)]; // half the size of chunk c 
    int e,l,t,k,m,rank,plus,minus; 
    int temp = (log(N)-log(p))/log(2); 
    //printf("temp = %d", temp); 

    for(e = 0; e < (log(p)/log(2)); e++){ 
    /* loop constants */ 
    t = pow(2,e); l = pow(2,e+temp); 
    q = n/2*l; z = cpow(w,(complex)q); 
    j = j-1; int v = pow(2,j); 

    if(e != 0){ 
     plus = (myid + p/v)%p; 
     minus = (myid - p/v)%p; 
    } else { 
     plus = myid + p/v; 
     minus = myid - p/v; 
    } 

    if(myid%t == myid%(2*t)){ 
     MPI_Recv((char*)&c, 
      sizeof(c), 
      MPI_BYTE, 
      plus, 
      MPI_ANY_TAG, 
      MPI_COMM_WORLD, 
      &status); 

     /* transform */ 
     for(k = 0; k < N/p; k++){ 
    m = (myid * N/p + k)%l; 
    c[k] = c[k] + c[k+N/v] * cpow(z,m); 
    c[k+N/v] = c[k] - c[k + N/v] * cpow(z,m); 
    printf("(k,k+N/v) = (%d,%d)\n",k,k+N/v); 
    }*/ 
     printf("\n\n"); 
     /* end transform */ 

     *block = get_block(c, N/v, N/v + N/p + 1); 
     MPI_Send((char*)&block, 
      sizeof(block), 
      MPI_BYTE, 
      plus, 
      1, 
      MPI_COMM_WORLD); 
    } else { 
     // send data of this PE to the (i- p/v)th PE 
     MPI_Send((char*)&c, 
      sizeof(c), 
      MPI_BYTE, 
      minus, 
      1, 
      MPI_COMM_WORLD); 
     // after the transformation, receive data from (i-p/v)th PE 
     //  and store them in c: 
     MPI_Recv((char*)&block, 
      sizeof(block), 
      MPI_BYTE, 
      minus, 
      MPI_ANY_TAG, 
      MPI_COMM_WORLD, 
       &status); 

     *c = put_block(block, c, N/v, N/v + N/p - 1); 
     //printf("Process %d send/receive %d\n",myid, plus); 
    } 
    } 
    /* shut down MPI */ 
    MPI_Finalize(); 
} 

/* helper functions */ 
double complex get_block(double complex *c, int start, int stop) 
{ 
    double complex block[stop - start + 1]; 
    //printf("%d = %d\n",sizeof(block)/sizeof(double complex), sizeof(&c)/sizeof(double complex)); 
    int j = 0; 
    int i; 
    for(i = start; i < stop+1; i++){ 
    block[j] = c[i]; 
    j = j+1; 
    } 
    return *block; 
} 


double complex put_block(double complex from[], double complex to[], int start, int stop) 
{ 
    int j = 0; 
    int i; 
    for(i = start; i<stop+1; i++){ 
    to[i] = from[j]; 
    j = j+1; 
    } 
    return *to; 
} 

我真的很感激反馈!

回答

1

您正在以错误的方式使用数组/指针指向数组。例如,您将一个数组声明为double复数块[N],这很好(尽管不常见,在大多数情况下最好使用malloc),然后通过MPI_Recv(&块)接收数组。然而,“块”已经是指向该数组的指针,因此通过编写“&块”,您将指针的指针传递给MPI_Recv。这不是它所期望的。如果你想使用“&”表示法,你必须编写& block [0],它会给你指向块数组的第一个元素的指针。

+0

我决定在另一个方向上使用我的代码,但'&'符号和指针的说明非常有帮助。谢谢! – Muttonchop

+2

实际上,数组名和指针之间存在细微差别。因为'block'是一个数组名,'block','&block'和'&block [0]'给出了相同的地址(试一下!),而如果'block'是一个指针变量,那么'&block'应该给出存储指针值的地址。所以你的答案完全错误。 –

+0

哇,谢谢你的澄清!我一直认为char * a和char a []是等价的 - 但它们不是! – timos

1

您是否尝试过调试您的代码?这可能是一个平行设置的痛苦,但它可以告诉你到底在哪里失败,通常也为什么

如果您正在使用Linux或OS X,你可以运行你的代码的命令行如下:

mpirun -np 4 xterm -e gdb -ex run --args ./yourprog yourargs 

在那里我假设yourprog是你的程序的名称和yourargs任何命令你想传递的参数。

此命令将执行的操作是启动四个xterm窗口。每个xterm依次按照选项-e的规定启动gdb。然后gdb将执行命令run,如选项-ex所指定的那样,并按照--args的规定使用给定的选项启动您的可执行文件。

你得到的是四个xterm与MPI同时运行程序的四个实例的窗口。如果任何实例崩溃,gdb会告诉你在哪里以及为什么。

+0

使用Open MPI,您还可以使用内置支持来启动'xterm':'mpirun -np 4 -xterm -1 gdb ...'或者甚至是'mpirun -np 4 -xterm -1 \! gdb ...'以防止gdb退出后'xterm'自动关闭。 –