2015-09-18 2 views
3

Я новичок в программировании MPI. У меня есть массив размером 8 на 10, который мне нужно использовать, чтобы найти суммирование каждой строки параллельно. В ранге 0 (процесс 0) он будет генерировать матрицу 8 на 10, используя 2-мерный массив. Затем я использовал бы номер tag как первое значение индекса (номер строки) массива. Таким образом, я могу использовать уникальный буфер для отправки через Isend. Тем не менее, похоже, что мой метод генерации номера тега для Isend не работает. Не могли бы вы взглянуть на следующий код и сказать, правильно ли я передаю 2D-массив и номер тега. Когда я запускаю этот код, он останавливается сразу после запуска rannk 1 и ждет. Я использую 3 процесса для этого примера и использую команду mpirun -np 3 test, пожалуйста, дайте мне знать, как решить эту проблему с примером, если это возможно.Как передать 2D-массив в MPI и создать динамическое значение тега с использованием языка C?

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

int main (int argc, char *argv[]) 
{ 
     MPI_Init(&argc, &argv); 
     int world_rank; 
     MPI_Comm_rank(MPI_COMM_WORLD, &world_rank); 
     int world_size; 
     MPI_Comm_size(MPI_COMM_WORLD, &world_size);   
     int tag = 1;   
     int arr[8][10]; 
     MPI_Request request; 
     MPI_Status status; 
     int source = 0; 
     int dest; 

     printf ("\n--Current Rank: %d\n", world_rank); 

     if (world_rank == 0) 
     { 
      int i = 0; 
      int a, b, x, y; 

      printf("* Rank 0 excecuting\n"); 

      for(a=0; a<8/(world_size-1); a++)//if -np is 3, this will loop 4 times 
      {   
       for(b=0; b<(world_size-1); b++)//if -np is 3, this loops will loop 2 times 
       {//So, if -np is 3, due to both of these loops, Isend will be called 8 times 
        dest = b+1;  
        tag = a+b;//create a uniqe tag value each time, which can be use as first index value of array 
        //Error: This tag value passing to Isend doesn't seems to be workiing 
        MPI_Isend(&arr[tag][0], 10, MPI_INT, dest, tag, MPI_COMM_WORLD, &request); 
       } 
      } 

      for(x=0; x<8; x++)//Generating the whole 8 by 10 2D array 
      { 
       i++; 
       for (y = 0; y < 10; y++) 
       { 
        arr[x][y] = i; 
       } 
      }    
     } 
     else 
     { 
      int a, b;     
      for(b=1; b<=8/(world_size-1); b++) 
      { 
       int sum = 0; 
       int i; 
       MPI_Irecv(&arr[tag][0], 10, MPI_INT, source, tag, MPI_COMM_WORLD, &request); 
       MPI_Wait (&request, &status);    
         //Error: not getting the correct tag value 
       for(i = 0; i<10; i++) 
       { 
        sum = arr[tag][i]+sum; 
       } 
       printf("\nSum is: %d at rank: %d and tag is:%d\n", sum, world_rank, tag); 
      }   
     } 
     MPI_Finalize(); 
} 

ответ

3

Проблема с тегом связана с тем, как тег вычисляется (или нет) на разных процессах. Вы инициализация значения тегов для всех процессов, как

int tag = 1; 

, а затем, для ранга процесса 0 Вы установите тег в

tag = a+b; 

, который, впервые это установлено, установят tag до 0, так как оба a и b начинаются как ноль. Однако для процессов с рангом выше 0 тег никогда не изменяется. Они будут по-прежнему иметь тег, установленный в 1.

Тег уникально идентифицирует сообщение, отправленное MPI_Isend и MPI_Irecv, что означает, что для отправки и соответствующего им получения должен иметь тот же самый тег для передачи данных для успеха. Поскольку теги несовместимы между процессами для большинства получателей, передачи в основном не увенчались успехом. Это приводит к тому, что процессы с рангом выше 0, чтобы в конечном итоге заблокировать (ожидание) на вызов до MPI_Wait.

Чтобы исправить это, вы должны обязательно изменить теги для процессов с рангом выше нуля. Однако, прежде чем мы сможем это сделать, есть еще несколько вопросов, которые стоит подправить.

С помощью того, как вы установили свой тег для процесса ранга 0 прямо сейчас, tag может иметь значения от 0 до 4 (при условии 3 процессов). Это связано с тем, что a ограничен диапазоном от 0 до 3, а b может иметь только значения 0 или 1. Максимальная возможная сумма этих значений равна 4. Это означает, что при доступе к вашему массиву с использованием arr[tag][0] вы пропустите много данных, и вы повторно отправляете одни и те же строки несколько раз. Я рекомендую изменить подход к отправке каждого подмассива (к которому вы в настоящее время обращаетесь с tag), так что у вас есть только один цикл для определения того, какой субмассив для отправки, а не два встроенных цикла. Затем, вы можете рассчитать процесс передачи массива в качестве

dest = subarray_index%(world_size - 1) + 1; 

Это будет чередовать desitnations между процессами с рангом больше нуля. Вы можете сохранить тег как subarray_index. На принимающей стороне вам нужно будет вычислить тег для каждого процесса за каждый прием.

Наконец, я увидел, что вы инициализировали массив после отправки данных. Вы хотите сделать это заранее.

Объединяя все эти аспекты, мы получаем

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

int main (int argc, char *argv[]) 
{ 
     MPI_Init(&argc, &argv); 
     int world_rank; 
     MPI_Comm_rank(MPI_COMM_WORLD, &world_rank); 
     int world_size; 
     MPI_Comm_size(MPI_COMM_WORLD, &world_size);   
     int tag = 1;   
     int arr[8][10]; 
     MPI_Request request; 
     MPI_Status status; 
     int source = 0; 
     int dest; 

     printf ("\n--Current Rank: %d\n", world_rank); 

     if (world_rank == 0) 
     { 
      int i = 0; 
      int a, b, x, y; 

      printf("* Rank 0 excecuting\n"); 
      //I've moved the array generation to before the sends. 
      for(x=0; x<8; x++)//Generating the whole 8 by 10 2D array 
      { 
       i++; 
       for (y = 0; y < 10; y++) 
       { 
        arr[x][y] = i; 
       } 
      } 

      //I added a subarray_index as mentioned above. 
      int subarray_index; 
      for(subarray_index=0; subarray_index < 8; subarray_index++) 
      { 
       dest = subarray_index%(world_size - 1) + 1;  
       tag = subarray_index; 
       MPI_Isend(&arr[subarray_index][0], 10, MPI_INT, dest, tag, MPI_COMM_WORLD, &request); 
      } 

     } 
     else 
     { 
      int a, b;     
      for(b=0; b<8/(world_size-1); b++) 
      { 
       int sum = 0; 
       int i; 
       //We have to do extra calculations here. These match tag, dest, and subarray. 
       int my_offset = world_rank-1; 
       tag = b*(world_size-1) + my_offset; 
       int subarray = b; 
       MPI_Irecv(&arr[subarray][0], 10, MPI_INT, source, tag, MPI_COMM_WORLD, &request); 
       MPI_Wait (&request, &status);    
       for(i = 0; i<10; i++) 
       { 
        sum = arr[subarray][i]+sum; 
       } 
       printf("\nSum is: %d at rank: %d and tag is:%d\n", sum, world_rank, tag); 
      }   
     } 
     MPI_Finalize(); 
} 

Там есть одна вещь, которая до сих пор кажется немного незавершенной в этой версии для Вас рассмотреть следующие вопросы: что произойдет, если ваш число процессов изменения? Например, если у вас есть 4 процесса, а не 3, похоже, вы можете столкнуться некоторые проблемы с петлей

for(b=0; b<8/(world_size-1); b++) 

, потому что каждый процесс будет выполнять это такое же количество раз, но количество данных, отправленных Безразлично Чисто расщепляется на 3 рабочих (без ранга-нулевых процессов).

Однако, если это вас не касается, вам не нужно обращаться с такими случаями.

+0

Большое спасибо за вашу помощь и показ с примером –

1

Помимо очевидного вопроса: «Почему бы вам это сделать?», Здесь так много проблем, что я не уверен, что смогу перечислить их все. Я дам ему попробовать, хотя:

  • Тэг: кажется, что большая часть вашего метода является использование тега в качестве индикатора, где искать приемника. Но есть (по крайней мере) две основные недостатки здесь:

    1. Поскольку tag не знаю, перед приемом, что это &arr[tag][0] должно быть?
    2. Метки в MPI - это идентификаторы сообщений «...» При нормальных обстоятельствах данное сообщение (отправка и сопоставление) должно иметь соответствующий тег. Это можно смягчить, используя специальный тег MPI_ANY_TAG на принимающей стороне и извлечение его фактического значения с помощью поля MPI_TAG статуса приема. Но это уже другая история.

    Нижняя линия здесь заключается в том, что метод не такой хороший.

  • инициализация

    данных: один из основных принципов неблокирующей коммуникаций MPI является то, что вы должны никогда изменить буфер вы использовали для связи между постом связи (далее MPI_Isend() здесь) и его завершением (который здесь отсутствует). Поэтому для генерации данных должно быть до попыток передачи данных.

  • Говоря об этом, окончание связи: у вас тоже завершите отправку сообщений. Это может быть сделано с помощью либо ожидания типа вызова (MPI_Wait() или MPI_Waitall()), или «бесконечный» цикл вызовов тест-типа (MPI_Test() и такие) ...

  • MPI_Irecv(): почему вы используете не -блокировка, когда следующий звонок равен MPI_Wait()? Если вы хотите заблокировать получение, просто позвоните MPI_Recv() напрямую.

В принципе, то, что вы пытаетесь сделать здесь, выглядит не так. Поэтому я очень неохотно пытаюсь предложить вам исправленную версию, так как я не понимаю, какую проблему вы пытаетесь решить. Является ли этот код уменьшенной версией более крупного реального (или начальной версии чего-то, что должно расти), или просто игрушечный пример, предназначенный для вас, чтобы узнать, как работает передача/прием MPI?Есть ли фундаментальная причина, почему вы не используете коллективную связь, такую ​​как MPI_Scatter()?

В зависимости от вашего ответа по этим вопросам я могу попытаться создать допустимую версию.

Смежные вопросы