C 如何循环这些MPI调用,或者为了保持整洁,如何将它们转换为函数并循环函数?

C 如何循环这些MPI调用,或者为了保持整洁,如何将它们转换为函数并循环函数?,c,loops,parallel-processing,mpi,C,Loops,Parallel Processing,Mpi,我几乎完成了这个程序,我只需要循环一段时间。目标是说,如果“旧能源”在“新能源”的一定范围内(程序中的旧能源与新能源),那么循环将终止并打印新能源。。。也就是说,这是一种能源优化。现在我只是试着循环,所以我做了一个y循环,循环三次。然而,当我运行程序时,它只是在终端中暂停。我不太清楚问题出在哪里。我认为这与内存分配有关,所以我尝试释放内存,并将其重新分配到最合理的位置 靠近中间I标记为//MAIN LOOP//的区域就是问题所在。如果试图将这么多的内容放入循环中似乎不合理,我如何修改它,例如通过

我几乎完成了这个程序,我只需要循环一段时间。目标是说,如果“旧能源”在“新能源”的一定范围内(程序中的旧能源与新能源),那么循环将终止并打印新能源。。。也就是说,这是一种能源优化。现在我只是试着循环,所以我做了一个y循环,循环三次。然而,当我运行程序时,它只是在终端中暂停。我不太清楚问题出在哪里。我认为这与内存分配有关,所以我尝试释放内存,并将其重新分配到最合理的位置

靠近中间I标记为
//MAIN LOOP//
的区域就是问题所在。如果试图将这么多的内容放入循环中似乎不合理,我如何修改它,例如通过将它的块放入函数中?我试着将MPI调用到函数中,但这对我不起作用

节目如下:

#include "stdio.h"
#include "stdlib.h"
#include "mpi.h"
#include "math.h"
#include "assert.h"

int main(int argc, char **argv) {

  int N = 32;
  int dim = 3;
  float a = 10.0; // size of 3D box
  int size, rank, i, j, k, q;
  float **C, **Csend, **Crecv;
  float rijx, rijy, rijz, rij, Vij, E, oldE;
  float stepsize = 0.05;

  double Start_time, End_time, Elapse_time;
  MPI_Status status;

  MPI_Init(&argc, &argv);
  MPI_Comm_size(MPI_COMM_WORLD, &size);
  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
  MPI_Request requests[2];


  float energies[size];

  float calc_energy(float **matrix) {
  E = 0;
  for(i = 1; i < N-1; i++) {
    for(j = i+1; j < N; j++) {
      rijx = pow((matrix[i][0] - matrix[j][0]),2);
      rijy = pow((matrix[i][1] - matrix[j][1]),2);
      rijz = pow((matrix[i][2] - matrix[j][2]),2);
      rij = pow((rijx + rijy + rijz),0.5);
      Vij = pow((1/rij),12) - pow((1/rij),6);
      E = E + Vij;
    }
  }
  return E;
  }

  float **alloc_2d_float(int N, int dim) {
    float *data = (float *)malloc(N*dim*sizeof(float));
    float **array= (float **)malloc(N*sizeof(float*));
    for(i=0; i<N; i++) {
      array[i] = &(data[dim*i]);
    }
    return array;
}

  Csend = alloc_2d_float(N,dim);
  Crecv = alloc_2d_float(N,dim);
  C = alloc_2d_float(N,dim);

if(rank==0){
  for (i = 0; i < N; i++) {
    for (j = 0; j < dim; j++) {
        Csend[i][j] = (float)rand()/(float)(RAND_MAX/a);
    }
  }
}

// This function is to take a random number of matrix elements and change them slightly, but with a catch which is that it should be different for each processor.
float **randomsteps(float **matrix) {
  float **newmatrix;
  newmatrix = alloc_2d_float(N,dim);

  for(i = 0; i < N; i = i++) {
    for (j = 0; j < dim; j++) {
      newmatrix[i][j] = matrix[i][j];
    }
  }

  int n = rand()%dim;
  for(i = 0; i < N; i = i+n) {
    for (j = 0; j < dim; j++) {
     int n = rand() % dim;
     if(i%2 == 0) {
       newmatrix[i][j] = matrix[i][j]+((rank+1)*stepsize);
       if(newmatrix[i][j] > 10) {
         newmatrix[i][j] = matrix[i][j] + (stepsize) - 10;
       }
     } else {
       newmatrix[i][j] = matrix[i][j]-((rank+1)*stepsize);
       if(newmatrix[i][j] < 0) {
         newmatrix[i][j] = matrix[i][j] - (stepsize) + 10;
       }
     }
   }
 }
 return newmatrix;
}

// MAIN LOOP //
int y; // var for big loop
for(y=0;y<3;y++) {
  for (i = 1; i < size; i++) {
    if (rank == 0) {
      MPI_Send(&(Csend[0][0]), N*dim, MPI_FLOAT, i, 10+i, MPI_COMM_WORLD);
    }
    if (rank == i) {
      MPI_Recv(&(Crecv[0][0]), N*dim, MPI_FLOAT, 0, 10+i, MPI_COMM_WORLD, &status);
     }
  }

if(rank==0){
  C = randomsteps(Csend);
  E = calc_energy(C);
  oldE = calc_energy(C);
  energies[0]=E;
} else {
  C = randomsteps(Crecv);
  E = calc_energy(C);
}

MPI_Barrier(MPI_COMM_WORLD);

for (i = 1; i < size; i++) {
  if (rank == i) {
    MPI_Send(&E, 1, MPI_FLOAT, 0, 10+i, MPI_COMM_WORLD);
  }
  if (rank == 0) {
    MPI_Recv(&energies[i], size-1, MPI_FLOAT, i, 10+i, MPI_COMM_WORLD, &status);
  }
}

MPI_Barrier(MPI_COMM_WORLD);

int location;
int findmin(float *energies) {
  int location = 1;
  float minimum = energies[0];

  for (i = 1 ; i < size ; i++ ) {
    if ( energies[i] < minimum ) {
      minimum = energies[i];
      location = i;
    }
  } 
  return location;
}

if(rank==0){
  location = findmin(energies);
}

MPI_Bcast(&location, 1, MPI_FLOAT, 0, MPI_COMM_WORLD);


if(rank==0){
  MPI_Recv(&(C[0][0]), N*dim, MPI_FLOAT, location, 1, MPI_COMM_WORLD, &status);
}
if(rank == location){
  MPI_Send(&(C[0][0]), N*dim, MPI_FLOAT, 0, 1, MPI_COMM_WORLD);
}

MPI_Barrier(MPI_COMM_WORLD);

if(rank==0){
  printf("%f\n",calc_energy(C));
  free(Csend);
  Csend = alloc_2d_float(N,dim);
  for(i=0;i<N;i++){
    for(j=0;j<dim;j++){
      Csend[i][j] = C[i][j];
}}
}

MPI_Barrier(MPI_COMM_WORLD);


free(C);
free(Crecv);
C = alloc_2d_float(N,dim);
Crecv = alloc_2d_float(N,dim);

MPI_Barrier(MPI_COMM_WORLD);

}
//END MAIN LOOP



free(C);
free(Csend);
free(Crecv);
MPI_Finalize();

return 0;
}
它被卡在两个优米之间

edit2:更具体地说,它似乎是
C=randomsteps(Crecv)这就是问题所在

edit3:在随机步骤中注释这段代码可以解决问题,所以这似乎是原因。还在想原因吗

  int n = rand()%dim;
  for(i = 0; i < N; i = i+n) {
    for (j = 0; j < dim; j++) {
      int n = rand() % dim;
      if(i%2 == 0) {
        newmatrix[i][j] = matrix[i][j]+((rank+1)*stepsize);
        if(newmatrix[i][j] > 10) {
          newmatrix[i][j] = matrix[i][j] + (stepsize) - 10;
        }
      } else {
        newmatrix[i][j] = matrix[i][j]-((rank+1)*stepsize);
        if(newmatrix[i][j] < 0) {
          newmatrix[i][j] = matrix[i][j] - (stepsize) + 10;
        }
      }
    }
  }
int n=rand()%dim;
对于(i=0;i10){
newmatrix[i][j]=矩阵[i][j]+(步长)-10;
}
}否则{
newmatrix[i][j]=矩阵[i][j]((秩+1)*步长);
if(newmatrix[i][j]<0){
新矩阵[i][j]=矩阵[i][j]-(步长)+10;
}
}
}
}
该代码试图获取矩阵中的随机元素,并在每个处理器上对它们的值进行轻微且唯一的修改(例如,0.05*秩)

edit4:啊,我想出来了。我只需要在
int n=rand()%dim中切换
dim
带有
N
。一个愚蠢的打字错误让我惊慌失措了三个小时-_-


也许我现在应该删除这个帖子?还是会关门?我不确定在这种情况下会怎么做,因为你的程序会挂起,因为你最终会陷入死锁

发生这种情况是因为发送/接收不平衡,请执行第一个循环:

  for (i = 1; i < size; i++) {
    if (rank == 0) {
      MPI_Send(&(Csend[0][0]), N*dim, MPI_FLOAT, i, 10+i, MPI_COMM_WORLD);
    }
    if (rank == i) {
      MPI_Recv(&(Crecv[0][0]), N*dim, MPI_FLOAT, 0, 10+i, MPI_COMM_WORLD, &status);
     }
  }

同样,在循环结束时相应地更改send/recv代码。

您的程序挂起仅仅是因为您最终陷入死锁

发生这种情况是因为发送/接收不平衡,请执行第一个循环:

  for (i = 1; i < size; i++) {
    if (rank == 0) {
      MPI_Send(&(Csend[0][0]), N*dim, MPI_FLOAT, i, 10+i, MPI_COMM_WORLD);
    }
    if (rank == i) {
      MPI_Recv(&(Crecv[0][0]), N*dim, MPI_FLOAT, 0, 10+i, MPI_COMM_WORLD, &status);
     }
  }

也相应地更改循环末尾的send/recv代码。

在main中有函数定义,这如何工作?不,但不应该使用允许嵌套函数工作的GCC扩展,但是我的第一条注释不清楚。您定义了float**alloc_2d_float(int rows,int cols)使用rows和cols,但在函数中不使用这两个参数。据我所知,它应该可以工作,因为嵌套函数可以看到上面函数中的变量。在findmin中有for循环whiteout指令和比需要更多的{}。很难遵循代码。(i=i++)循环中应该只有i++我知道,我清理了它,现在它编译了。从for循环中,我了解到您必须使用4个处理器来执行它,但根本没有检查,数字只是放在那里。MPI程序也只能使用一个处理器,这是一个很好的实践。至少调试起来容易多了。你在main中有函数定义,这是如何工作的?不,但你不应该使用它是一个允许嵌套函数工作的GCC扩展,但是我的第一条评论不清楚。你定义了float**alloc\u 2d\u float(int rows,int cols)使用rows和cols,但在函数中不使用这两个参数。据我所知,它应该可以工作,因为嵌套函数可以看到上面函数中的变量。在findmin中有for循环whiteout指令和比需要更多的{}。很难遵循代码。(i=i++)循环中应该只有i++我知道,我清理了它,现在它编译了。从for循环中,我了解到您必须使用4个处理器来执行它,但根本没有检查,数字只是放在那里。MPI程序也只能使用一个处理器,这是一个很好的实践。至少调试起来容易多了。
  if (rank == 0) {
    for (i = 1; i < size; i++)
      MPI_Send(&(Csend[0][0]), N*dim, MPI_FLOAT, i, 10+i, MPI_COMM_WORLD);
  }
  if (rank == i) {
    MPI_Recv(&(Crecv[0][0]), N*dim, MPI_FLOAT, 0, 10+i, MPI_COMM_WORLD, &status);
  }