Нужна помощь в понимании MPI_Comm_create

Что касается MPI_Comm_create, стандарт MPI гласит

MPI_COMM_CREATE(комм, группа, новый комм)

... Функция является коллективной и должна вызываться всеми процессами в группе комм.

Я понял, что это означает, что, например, если аргумент comm - MPI_COMM_WORLD, то все процессы должны вызывать MPI_COMM_WORLD.

Тем не менее, я написал вариант кода, доступного в Интернете, демонстрирующий использование MPI_Comm_create. Это ниже. Вы можете видеть, что есть два места, где вызывается MPI_Comm_create, и не всеми процессами. И все же код работает просто отлично.

Мне повезло? Я наткнулся на некоторые зависящие от реализации функции? Я неправильно понимаю стандарт MPI? Является ли идея, что два вызова вместе приводят к тому, что каждый вызывает MPI_Comm_create, так что "в конце дня" все в порядке? Благодарю. Вот код:

#include <stdio.h>
#include <stdlib.h>
#include "mpi.h"


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

   MPI_Comm even_comm, odd_comm;
   MPI_Group even_group, odd_group, world_group;
   int id, even_id, odd_id;
   int *even_ranks, *odd_ranks;
   int num_ranks, num_even_ranks, num_odd_ranks;
   int err_mpi, i, j;
   int even_sum, odd_sum;


   err_mpi = MPI_Init(&argc, &argv);
   MPI_Comm_size(MPI_COMM_WORLD, &num_ranks);
   MPI_Comm_rank(MPI_COMM_WORLD, &id);

   MPI_Comm_group(MPI_COMM_WORLD, &world_group);

   num_even_ranks = (num_ranks+1)/2;
   even_ranks = (int *)malloc(num_even_ranks*sizeof(int));
   j=0;
   for (i=0; i<num_ranks; i++){
      if (i%2 == 0) {
         even_ranks[j] = i;
         j++;
      }
   } 

   num_odd_ranks = num_ranks/2;
   odd_ranks = (int *)malloc(num_odd_ranks*sizeof(int));
   j=0;
   for (i=0; i<num_ranks; i++){
      if (i%2 == 1) {
         odd_ranks[j] = i;
         j++;
      }
   } 

   if (id%2 == 0){
      MPI_Group_incl(world_group, num_even_ranks, even_ranks, &even_group);
      // RIGHT HERE, all procs are NOT calling!
      MPI_Comm_create(MPI_COMM_WORLD, even_group, &even_comm);
      MPI_Comm_rank(even_comm, &even_id);
      odd_id = -1;
   } else {
      MPI_Group_incl(world_group, num_odd_ranks, odd_ranks, &odd_group);
      // RIGHT HERE, all procs are NOT calling!
      MPI_Comm_create(MPI_COMM_WORLD, odd_group, &odd_comm);
      MPI_Comm_rank(odd_comm, &odd_id);
      even_id = -1;
   }

   // Just to have something to do, we'll some up the ranks of
   // the various procs in each communicator.       
   if (even_id != -1) MPI_Reduce(&id, &even_sum, 1, MPI_INT, MPI_SUM, 0, even_comm);
   if (odd_id != -1) MPI_Reduce(&id, &odd_sum, 1, MPI_INT, MPI_SUM, 0, odd_comm);

   if (odd_id == 0) printf("odd sum: %d\n", odd_sum);
   if (even_id == 0) printf("even sum: %d\n", even_sum);

   MPI_Finalize();

}

1 ответ

Решение

Хотя comm_create вызывается из двух разных строк кода, важно отметить, что все процессы в COMM_WORLD одновременно вызывают comm_create. Тот факт, что они не из одной строки кода, не имеет значения - фактически, библиотека MPI даже не знает, откуда вызывается comm_create.

Более простой пример - вызов барьера из двух ветвей; независимо от того, какая строка выполняется, все процессы выполняют один и тот же барьер, поэтому код будет работать так, как ожидается.

Вы можете легко переписать код, который будет вызываться из той же строки: просто иметь переменные с именами "num_ranks", "mycomm", "mygroup" и "myid" и массив с именем "ranks" и устанавливать их равными четным или нечетным переменным в зависимости от ранга. Все процессы могут затем вызывать:

MPI_Group_incl(world_group, num_ranks, ranks, &mygroup);
MPI_Comm_create(MPI_COMM_WORLD, mygroup, &mycomm);
MPI_Comm_rank(mycomm, &myid);

и если вы действительно хотите, вы можете переназначить их потом, например,

if (id%2 == 0) even_comm = mycomm;
Другие вопросы по тегам