有什么方法可以避免这种隐式MPI_Allreduce()同步?

时间:2018-08-07 12:30:56

标签: mpi

我正在编写一个MPI程序,该程序使用一个进行自身MPI调用的库。在我的程序中,有一个循环从库中调用一个函数。我从库中调用的函数使用了MPI_Allreduce

这里的问题是,在我的程序中,某些等级可以在其他等级之前退出循环,这会导致MPI_Allreduce调用挂起,因为并非所有等级都将再次调用MPI_Allreduce

是否可以在不修改我正在使用的库源代码的情况下对此进行编程?

下面是一个示例代码,演示了执行模式。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <mpi.h>
#include <math.h>
#include <assert.h>

#define N_ITEMS 100000
#define ITERATIONS 32 

float *create_rand_nums(int num_elements) {
  float *rand_nums = (float *)malloc(sizeof(float) * num_elements);
  assert(rand_nums != NULL);
  int i;
  for (i = 0; i < num_elements; i++) {
    rand_nums[i] = (rand() / (float)RAND_MAX);
  }
  return rand_nums;
}

void reduce_stddev(int world_rank, int world_size, int num_elements_per_proc)
{
  fprintf(stdout, "Calling %s: %d\n", __func__, world_rank);
  fflush(stdout);

  srand(time(NULL)*world_rank);
  float *rand_nums = NULL;
  rand_nums = create_rand_nums(num_elements_per_proc);

  float local_sum = 0;
  int i;
  for (i = 0; i < num_elements_per_proc; i++) {
    local_sum += rand_nums[i];
  }

  float global_sum;
  fprintf(stdout, "%d: About to call all reduce\n", world_rank);
  fflush(stdout);
  MPI_Allreduce(&local_sum, &global_sum, 1, MPI_FLOAT, MPI_SUM,
                MPI_COMM_WORLD);
  fprintf(stdout, "%d: done calling all reduce\n", world_rank);
  fflush(stdout);
  float mean = global_sum / (num_elements_per_proc * world_size);

  float local_sq_diff = 0;
  for (i = 0; i < num_elements_per_proc; i++) {
    local_sq_diff += (rand_nums[i] - mean) * (rand_nums[i] - mean);
  }

  float global_sq_diff;
  MPI_Reduce(&local_sq_diff, &global_sq_diff, 1, MPI_FLOAT, MPI_SUM, 0,
             MPI_COMM_WORLD);

  if (world_rank == 0) {
    float stddev = sqrt(global_sq_diff /
                        (num_elements_per_proc * world_size));
    printf("Mean - %f, Standard deviation = %f\n", mean, stddev);
  }

  free(rand_nums);
}

int main(int argc, char* argv[]) {
  if (argc != 2) {
    fprintf(stderr, "Usage: avg num_elements_per_proc\n");
    exit(1);
  }

  int num_elements_per_proc = atoi(argv[1]);

  MPI_Init(NULL, NULL);

  int world_rank;
  MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
  int world_size;
  MPI_Comm_size(MPI_COMM_WORLD, &world_size);

  unsigned long long j = 0;

  for(j = 0; j < ITERATIONS; j++)
  {
    /* Function which calls MPI_Allreduce */
    reduce_stddev(world_rank, world_size, num_elements_per_proc);

    /* Simulates some processes leaving the loop early */
    if( (j == (ITERATIONS/2)) && (world_rank % 2 == 0))
    {
      fprintf(stdout, "%d exiting\n", world_rank);
      fflush(stdout);
      break;
    }
  }

  MPI_Barrier(MPI_COMM_WORLD);
  MPI_Finalize();

  return EXIT_SUCCESS;
}

1 个答案:

答案 0 :(得分:1)

这在MPI中始终是一个问题-当一个等级结束时,您如何告诉所有其他等级?最简单的方法是让每个人都设置一个true / false标志,然后进行减少操作以查看是否有人完成了操作。最后使用此代码似乎可行

  for(j = 0; j < ITERATIONS; j++)
    {
      /* Function which calls MPI_Allreduce */
      reduce_stddev(world_rank, world_size, num_elements_per_proc);

      int finished = 0;

      /* Simulates some processes leaving the loop early */
      if( (j == (ITERATIONS/2)) && (world_rank % 2 == 0))
      {
        fprintf(stdout, "%d finished\n", world_rank);
        fflush(stdout);
        finished = 1;
      }

      /* Check to see if anyone has finished */

      int anyfinished;

      MPI_Allreduce(&finished, &anyfinished, 1, MPI_INT, MPI_LOR,
        MPI_COMM_WORLD);

      if (anyfinished)
      {
         fprintf(stdout, "%d exiting\n", world_rank);
         break;
      }
   }

好的-我只是重新阅读了你的问题,也许我误解了。您是否要其他所有人继续计算?