使用MPI_Isend和MPI_Irecv而不是MPI_Bcast将广播消息定时到所有处理器

时间:2015-10-09 00:37:50

标签: c parallel-processing mpi

我有一个项目,我需要使用MPI_Isend和MPI_Irecv计算任何错误的MPI_Bcast实现,并将其与MPI_Bcast进行比较。因为这些程序的时间是0.000000秒,我需要使用一个大型数组(正如我所做的那样)。我的代码中还没有的是for循环和MPI_Irecv / Isend函数应该在循环中以使程序花费大量的时间来完成。

这是我的代码,我将在下面讨论我遇到的问题:

#include <stdio.h>
#include <string.h>
#include <mpi.h>

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

  int a = 1000000000;
  int i, N;
  int Start_time, End_time, Elapse_Time;
  int proc_rank, partner, world_size;
  MPI_Status stat;
  float mydata[a];
  MPI_Request request;

  MPI_Init(&argc,&argv);
  MPI_Comm_rank(MPI_COMM_WORLD, &proc_rank);
  MPI_Comm_size(MPI_COMM_WORLD, &world_size);

  Start_time = MPI_Wtime();

  for (i = 0; i < a; i++) {
    mydata[i] = 0.2567*i;
  }

  MPI_Irecv(mydata, a, MPI_BYTE, 0, 1, MPI_COMM_WORLD, &request);

  MPI_Isend(mydata, a, MPI_BYTE, 0, 1, MPI_COMM_WORLD, &request);

  End_time = MPI_Wtime();
  Elapse_Time = End_time - Start_time;
  printf("Time on process %d is %f Seconds.\n", proc_rank, Elapse_Time);

  MPI_Finalize;

return 0;
}

当我使用命令mpirun -np 4 ./a.out运行时,我只得到一个处理器的时间,但我不确定为什么。我想我只是不了解这些功能是如何工作的,或者我应该如何使用它们。

感谢您的帮助!

2 个答案:

答案 0 :(得分:3)

您的代码中存在一些不同的问题,所有这些问题都可能导致崩溃或行为异常:

  • 正如@Olaf已经提到的,在堆栈上分配数组mydata是一个非常糟糕的主意。对于这么大的数组,你肯定应该在堆上进行分配,并显式调用malloc()。即便如此,你在这里玩的是一些严重的记忆,所以要小心不要耗尽机器上可用的东西。此外,一些MPI库难以处理大小超过2GB的消息,这是您的情况。所以再次注意这一点。
  • 您使用mydata作为发送和接收目的。但是,一旦您发布了非阻止通信,在通信完成之前无法重复使用相应的消息。因此,在您的情况下,您需要两个阵列,一个用于发送,一个用于接收。
  • 您传递给MPI调用的数据类型,即MPI_BYTE,与您传输的数据的实际类型(即float不一致。您应该使用MPI_FLOAT代替。
  • 如果不调用任何有效的MPI_Irecv()MPI_Isend()函数,即可致电MPI_Wait()MPI_Test()。这是错误的,因为这意味着通信可能永远不会发生。
  • MPI_Wtime()返回double,而不是int。这不是本身的错误,但可能会导致意外结果。此外,调用printf()时请求的格式对应于浮点数据,而不是整数,因此您必须使其一致。
  • (次要 - 错字)您错过了()的{​​{1}}。
  • (次要 - 我猜)你只与进程#0 ...
  • 进行通信

所以这是一个可行的工作代码版本:

MPI_Finalize()

注意:为了让代码在所有情况下工作,我在这里实现了一个通信环,进程0发送到进程1并从进程大小-1接收...但是,在你的重新上下文中实现广播,您可以忽略这一点(即#include <stdio.h> #include <string.h> #include <stdlib.h> #include <assert.h> #include <mpi.h> int main(int argc, char **argv) { int a = 1000000000; int i, from, to; double Start_time, End_time, Elapse_Time; int proc_rank, world_size; float *mysenddata, *myrecvdata; MPI_Request requests[2]; MPI_Init( &argc, &argv ); MPI_Comm_rank( MPI_COMM_WORLD, &proc_rank ); MPI_Comm_size( MPI_COMM_WORLD, &world_size ); Start_time = MPI_Wtime(); mysenddata = (float*) malloc( a * sizeof( float ) ); myrecvdata = (float*) malloc( a * sizeof( float ) ); assert( mysenddata != NULL ); /*very crude sanity check */ assert( myrecvdata != NULL ); /*very crude sanity check */ for ( i = 0; i < a; i++ ) { mysenddata[i] = 0.2567 * i; } from = ( proc_rank + world_size - 1 ) % world_size; to = ( proc_rank + 1 ) % world_size; MPI_Irecv( myrecvdata, a, MPI_FLOAT, from, 1, MPI_COMM_WORLD, &requests[0] ); MPI_Isend( mysenddata, a, MPI_FLOAT, to, 1, MPI_COMM_WORLD, &requests[1] ); MPI_Waitall( 2, requests, MPI_STATUSES_IGNORE ); End_time = MPI_Wtime(); Elapse_Time = End_time - Start_time; printf( "Time on process %d is %f Seconds.\n", proc_rank, Elapse_Time ); free( mysenddata ); free( myrecvdata ); MPI_Finalize(); return 0; } from参数)。

答案 1 :(得分:0)

我看到的唯一解释是你的另一个进程在打印之前崩溃了。尝试将代码的某些部分放在注释中并重新执行代码。

尝试这种方式,看看你是否看到差异

  MPI_Init(&argc,&argv);
  MPI_Comm_rank(MPI_COMM_WORLD, &proc_rank);
  MPI_Comm_size(MPI_COMM_WORLD, &world_size);

  /*Start_time = MPI_Wtime();

  for (i = 0; i < a; i++) {
    mydata[i] = 0.2567*i;
  }

  MPI_Irecv(mydata, a, MPI_BYTE, 0, 1, MPI_COMM_WORLD, &request);

  MPI_Isend(mydata, a, MPI_BYTE, 0, 1, MPI_COMM_WORLD, &request);

  End_time = MPI_Wtime();
  Elapse_Time = End_time - Start_time;*/
  printf("I'm process %d.\n", proc_rank);

  MPI_Finalize;