2017-01-19 4 views
1

У меня есть на каждом процессоре список range с номерами. Я хочу определить максимальное количество каждой строки этих списков range.Эффективное использование MPI_Allreduce

enter image description here

Первые четыре списка range для каждого процессора P0-P3. Красный список содержит максимальные значения каждой строки, которые получает каждый процессор после MPI_Allreduce.

Вот рабочая версия моего кода:

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

//#define KEY_MAX 100 

typedef struct{ 
    int myrank; 
    int numprocs; 
    int *range; 
} SubDomainKeyTree; 

void compRange(SubDomainKeyTree *s, int myrank, int numprocs){ 
    s->myrank = myrank; 
    s->numprocs = numprocs; 

    // Allocate memory for (numprocs+1) ranges 
    s->range = malloc((numprocs+1) * sizeof(int)); 
    // Compute range values 
    for(int p=0; p<=numprocs; p++){ 
     s->range[p] = rand()%100; 
    } 

    for(int p=0; p<s->numprocs; p++){ 
     if(s->myrank == p){ 
     for(int k=0; k<=s->numprocs; k++){ 
      printf("Processor %d: %d random number is %d\n", p, k, s->range[k]); 
     } 
     printf("\n"); 
     } 
    } 
    } 

    void compDynRange(SubD *s){ 

     int rangeForAll[s->numprocs+1]; 
     ////////////////////////////////// 
     // This is not really efficient // 
     ////////////////////////////////// 
     for(int r=0; r<=s->numprocs; r++){ 
      MPI_Allreduce(&s->range[r], &rangeForAll[r], 1, MPI_INT, MPI_MAX, MPI_COMM_WORLD); 
     } 

    for(int p=0; p<s->numprocs; p++){ 
     if(s->myrank == p){ 
      for(int k=0; k<=s->numprocs; k++){ 
       s->range[k] = rangeForAll[k]; 
       printf("Processor %d: %d random number after MPI_Allreduce is %d\n", p, k, s->range[k]); 
      } 
      printf("\n"); 
     } 
    } 
} 

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

    int nameLen; 
    char processorName[MPI_MAX_PROCESSOR_NAME]; 

    int myrank;   // Rank of processor 
    int numprocs;   // Number of processes 
    MPI_Init(&argc, &argv); 
    MPI_Comm_rank(MPI_COMM_WORLD, &myrank); 
    MPI_Comm_size(MPI_COMM_WORLD, &numprocs); 
    MPI_Get_processor_name(processorName,&nameLen); 
    MPI_Status status; 

    time_t t; 
    srand((unsigned)time(NULL)+myrank*numprocs+nameLen); 

    SubD s; 
    compRange(&s, myrank, numprocs); 

    compDynRange(&s); 
    MPI_Finalize(); 
    return 0; 
} 

Я использую для цикла, который кажется крайне неэффективным для меня. Здесь я вычисляю максимальное значение каждой строки всех списков один за другим.

Но могу ли я использовать MPI_Allreduce без этого для петли?

Я уже пробовал, что вместо петли, которая не работает.

MPI_Allreduce(&s->range, &rangeForAll, s->numprocs+1, MPI_INT, MPI_MAX, MPI_COMM_WORLD);

Может кто-нибудь дать мне подсказку, как я могу сделать это?

+2

Вы действительно использовали '&' как в своем вопросе? Если да, просто удалите их из вызова в 'MPI_Allreduce()', и это должно просто работать ... – Gilles

+0

@ Gilles Perfect! Это работает! – Samuel

ответ

1

Как уже было указано в комментарии, ошибка, которую вы имели в своем коде, заключалась в том, что вместо передачи массивов, содержащих ваши буферы отправки и получения, вы передавали им некоторые указатели. Я предполагаю, что эта ошибка просто пришла к изменению из одного элемента, который использовался первоначально (например, &s->range[r]), который был совершенно верным, до полного массива, просто удалив индексированный доступ (то есть &s->range), который был неправильным.

Так как объяснено, используя:

MPI_Allreduce(s->range, rangeForAll, s->numprocs+1, MPI_INT, MPI_MAX, MPI_COMM_WORLD) 

просто делает трюк. Однако, поскольку вы хотите получить результаты в массивы s->range, а не временные rangeFarAll, вам лучше не определять позднее, и использовать ключевое слово MPI_IN_PLACE в качестве параметра отправки и s->range в качестве получающего. Вызов становится:

MPI_Allreduce(MPI_IN_PLACE, s->range, s->numprocs+1, MPI_INT, MPI_MAX, MPI_COMM_WORLD) 

и s->range действует как отправка и получение буфера. Таким образом, окончательные результаты будут все в буферах s->range после вызова, избавив вас от необходимости делать копию явно.